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函数将它设为非触发态。

原文地址:https://www.cnblogs.com/java20130722/p/3207198.html