zoukankan      html  css  js  c++  java
  • Chapter09"内核模式下的线程同步"之事件内核对象

           有两种事件内核对象:自动事件和手动事件。当手动事件被触发时,所以该事件的等待线程都编程可调度状态;而自动事件被触发时,只有个一个等待该事件线程变成可调度状态。

           下面再逐个讲解Event的相关函数:

    a)       创建事件函数——CreateEvent函数

               HANDLE CreateEvent(
                                       PSECURITY_ATTRIBUTESpsa,
                                       BOOLbManualReset,
                                       BOOLbInitialState,
                                       PCTSTRpszName);
              具体的函数参数及用法,请查看上面的超链接。

    b)       第二创建事件的函数——CreateEventEx函数
               HANDLE CreateEventEx(
                                       PSECURITY_ATTRIBUTESpsa,
                                       PCTSTRpszName,
                                       DWORDdwFlags,
                                       DWORDdwDesiredAccess);

    c)       访问某个打开的事件(Event)——OpenEvent函数
               HANDLE OpenEvent(
                                       DWORDdwDesiredAccess,
                                       BOOLbInherit,
                                       PCTSTRpszName)
              在pszName传递创建事件时函数的pszName参数值。

    d)       使得某个事件处于触发状态——SetEvent函数
              BOOL SetEvent(HANDLE hEvent);

    e)       将某个事件设置为非触发状态——ResetEvent函数
              BOOL ResetEvent(HANDLE hEvent);

    f)        特别的函数——PluseEvent函数
              BOOL PulseEvent(HANDLE hEvent);
             其作用相当于在调用SetEvent函数后立即调用ResetEvent函数,功能就是一次启用一个线程。因为手动方式的事件时,当事件触发时,所有的该事件阻塞的线程都会转为可调度状态。如果你调用PluseEvent函数后,在系统调用某一个线程后,由于立马将事件设置为非触发状态,这是其他线程也就再次被阻塞了。解释起来好像比较麻烦,不过该函数在实际使用过程中也少有用到。

    看一个创建事件时设置手动方式的事件(manual-reset events)示例:

    // Create a global handle to a manual-reset, nonsignaled event.
    HANDLE g_hEvent;
    int WINAPI _tWinMain(...) {
    // Create the manual-reset, nonsignaled event.
    g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    // Spawn 3 new threads.
    HANDLE hThread[3];
    DWORD dwThreadID;
    hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
    hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
    hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);
    OpenFileAndReadContentsIntoMemory(...);
    // Allow all 3 threads to access the memory.
    SetEvent(g_hEvent);
    ...
    }
    DWORD WINAPI WordCount(PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }
    DWORD WINAPI SpellCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }
    DWORD WINAPI GrammarCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }

    创建事件时设置为自动方式时的事件(auto-reset event)示例:

    // Create a global handle to a auto-reset, nonsignaled event.
    HANDLE g_hEvent;
    int WINAPI _tWinMain(...) {
    // Create the auto-reset, nonsignaled event.
    g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    // Spawn 3 new threads.
    HANDLE hThread[3];
    DWORD dwThreadID;
    hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
    hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
    hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);
    OpenFileAndReadContentsIntoMemory(...);
    // Allow all 3 threads to access the memory.
    SetEvent(g_hEvent);
    ...
    }
    DWORD WINAPI WordCount(PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }
    DWORD WINAPI SpellCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }
    DWORD WINAPI GrammarCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }

          
    分析:

          对比上面的代码示例,细心的话你会发现:在自动方式下的代码中,每个线程在返回前都会调用SetEvent函数将事件设置为触发状态;而手动方式事件对应的函数中没有调用这个函数。
          这是因为在自动方式下,事件每次转化为触发状态时只能使一个线程变成可调度状态,为了让其他线程也能被执行,所以在每个线程返回前再次将事件设置为触发状态,使得其他等待该事件的线程转为可调度状态从而被执行。
          而手动方式下,则不同,当手动方式事件被SetEvent函数触发一次,它就一直保持触发态,直到再次调用ReSetEvent函数将它设为非触发态。

  • 相关阅读:
    leetcode 48. Rotate Image
    leetcode 203. Remove Linked List Elements 、83. Remove Duplicates from Sorted List 、82. Remove Duplicates from Sorted List II(剑指offer57 删除链表中重复的结点) 、26/80. Remove Duplicates from Sorted ArrayI、II
    leetcode 263. Ugly Number 、264. Ugly Number II 、313. Super Ugly Number 、204. Count Primes
    leetcode 58. Length of Last Word
    安卓操作的一些问题解决
    leetcode 378. Kth Smallest Element in a Sorted Matrix
    android studio Gradle Build速度加快方法
    禁用gridview,listview回弹或下拉悬停
    Android Studio找不到FragmentActivity类
    安卓获取ListView、GridView等滚动的距离(高度)
  • 原文地址:https://www.cnblogs.com/java20130722/p/3207198.html
Copyright © 2011-2022 走看看