多线程同步之Event(主要用来线程间的等待通知)
一 Event
在所有的内核对象中,事件内核对象是个最基本的对象。它们包含一个使用计数(与所有内核对象一样),一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
事件能够通知一个操作已经完成。有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。
Microsoft为自动重置的事件定义了应该成功等待的副作用规则,即当线程成功地等待到该对象时,自动重置的事件就会自动重置到未通知状态。这就是自动重置的事件如何获得它们的名字的方法。通常没有必要为自动重置的事件调用ResetEvent函数,因为系统会自动对事件进行重置。但是,Microsoft没有为人工重置的事件定义成功等待的副作用,所以需要调用ResetEvent()。
二 Event API
Event function |
Description |
CreateEvent |
Creates or opens a named or unnamed event object. |
CreateEventEx |
Creates or opens a named or unnamed event object and returns a handle to the object. |
OpenEvent |
Opens an existing named event object. |
PulseEvent |
Sets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads. |
ResetEvent |
Sets the specified event object to the nonsignaled state. |
SetEvent |
Sets the specified event object to the signaled state. |
三 代码实例
1)使用手动的Event:当文件读入内存的时候,WordCount, SpellCheck,GrammarCheck可以同时进行,这里使用Event,当文件一读入内存就通知WordCount,SpellCheck和GrammarCheck线程开始执行。
#include <windows.h>
#include <process.h>
#include <stdio.h>
// a global handle to event.
HANDLE g_hEvent;
void OpenFileAndReadContentsIntoMemory();
unsigned __stdcall WordCount(void *pvParam);
unsigned __stdcall SpellCheck(void *pvParam);
unsigned __stdcall GrammarCheck(void *pvParam);
int main()
{
//Create the manual-reset, nonsignaled event.
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//Spawn 3 new threads.
HANDLE hThread[3];
unsigned dwThreadID[3];
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID[0]);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID[1]);
hThread[2] = (HANDLE)_beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID[2]);
OpenFileAndReadContentsIntoMemory();
//Allow all 3 threads to access the memory.
SetEvent(g_hEvent);
printf("main thread exit\n");
return 1;
}
void OpenFileAndReadContentsIntoMemory()
{
printf("Open File and Read contents into memory\n");
}
unsigned __stdcall WordCount(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("0:word count\n");
return(0);
}
unsigned __stdcall SpellCheck(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("1:Spell check\n");
return(0);
}
unsigned __stdcall GrammarCheck(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("2:Grammar check\n");
return(0);
}
2)修改上面的代码,使用自动Event,则必须在3个子线程中增加SetEvent()。且要想让3个线程都执行完,必须的增加Waitfor()函数。
#include <windows.h>
#include <process.h>
#include <stdio.h>
// a global handle to event.
HANDLE g_hEvent;
void OpenFileAndReadContentsIntoMemory();
unsigned __stdcall WordCount(void *pvParam);
unsigned __stdcall SpellCheck(void *pvParam);
unsigned __stdcall GrammarCheck(void *pvParam);
int main()
{
//Create the AUTO-reset, nonsignaled event.
g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
//Spawn 3 new threads.
HANDLE hThread[3];
unsigned dwThreadID[3];
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID[0]);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID[1]);
hThread[2] = (HANDLE)_beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID[2]);
OpenFileAndReadContentsIntoMemory();
//Allow all 3 threads to access the memory.
SetEvent(g_hEvent);
//wait for child threads to exit
DWORD dwCThd = WaitForMultipleObjects (3, //count of objects
hThread, //thread handle
TRUE, //wait for all
INFINITE); //time out interval
if(dwCThd != WAIT_OBJECT_0)
{
printf("error\n");
exit(-1);
}
//close handles
CloseHandle (g_hEvent);
//close child thread handles
for (int i=0; i<3; i++)
CloseHandle (hThread[i]);
printf("main thread exit\n");
return 1;
}
void OpenFileAndReadContentsIntoMemory()
{
printf("Open File and Read contents into memory\n");
}
unsigned __stdcall WordCount(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("0:word count\n");
SetEvent(g_hEvent);
return(0);
}
unsigned __stdcall SpellCheck(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("1:Spell check\n");
SetEvent(g_hEvent);
return(0);
}
unsigned __stdcall GrammarCheck(void *pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
printf("2:Grammar check\n");
SetEvent(g_hEvent);
return(0);
}
四 参考
windows核心编程