多線程同步之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核心編程