不得不說官方的例子寫的是真的好,比網上亂七八糟代碼好太多了,以後參考代碼都以MSDN爲主。
先介紹一下CreateEvent這個函數的各個參數,這是重點
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全屬性
BOOL bManualReset,// 復位方式
BOOL bInitialState,// 初始狀態
LPCTSTR lpName // 對象名稱
);
第一個參數一般傳NULL,不多說;
第二個參數就有講究了,傳TRUE的時候需要手動置爲無信號狀態(即手動調用ResetEvent),意思是當事件處於有信號狀態的時候 所有的線程調用WaitForSingleObject都會成功,因爲一直是有信號的——即線程的同時運行,傳FALSE的時候,當一個線程調用(WaitForSingleObject)則會自動置爲無信號狀態,即其他線程調用WaitForSingleObject都會阻塞等待,因爲已經無信號了,除非調用線程結束或者調用線程主動調用了SetEvent,使事件處於有信號狀態——即線程的互斥執行。
第三個參數就是創建事件後,事件是否處於有信號狀態,TRUE則有否則無。
第四個參數是事件對象的字符串名稱。
下面這個Demo是模擬主線程寫、四個子線程同時讀的情況,代碼來自官方文檔。(由於需要線程的同時運行,採用手動置信號的形式,即第二個參數爲TRUE)
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 4
HANDLE ghWriteEvent;
HANDLE ghThreads[THREADCOUNT];
DWORD WINAPI ThreadProc(LPVOID);
void CreateEventsAndThreads(void)
{
int i;
DWORD dwThreadID;
// Create a manual-reset event object. The write thread sets this
// object to the signaled state when it finishes writing to a
// shared buffer.
ghWriteEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
if (ghWriteEvent == NULL)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return;
}
// Create multiple threads to read from the buffer.
for(i = 0; i < THREADCOUNT; i++)
{
// TODO: More complex scenarios may require use of a parameter
// to the thread procedure, such as an event per thread to
// be used for synchronization.
ghThreads[i] = CreateThread(
NULL, // default security
0, // default stack size
ThreadProc, // name of the thread function
NULL, // no thread parameters
0, // default startup flags
&dwThreadID);
if (ghThreads[i] == NULL)
{
printf("CreateThread failed (%d)\n", GetLastError());
return;
}
}
}
void WriteToBuffer(VOID)
{
// TODO: Write to the shared buffer.
printf("Main thread writing to the shared buffer...\n");
// Set ghWriteEvent to signaled
if (! SetEvent(ghWriteEvent) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return;
}
}
void CloseEvents()
{
// Close all event handles (currently, only one global handle).
CloseHandle(ghWriteEvent);
}
int main( void )
{
DWORD dwWaitResult;
// TODO: Create the shared buffer
// Create events and THREADCOUNT threads to read from the buffer
CreateEventsAndThreads();
// At this point, the reader threads have started and are most
// likely waiting for the global event to be signaled. However,
// it is safe to write to the buffer because the event is a
// manual-reset event.
WriteToBuffer();
printf("Main thread waiting for threads to exit...\n");
// The handle for each thread is signaled when the thread is
// terminated.
dwWaitResult = WaitForMultipleObjects(
THREADCOUNT, // number of handles in array
ghThreads, // array of thread handles
TRUE, // wait until all are signaled
INFINITE);
switch (dwWaitResult)
{
// All thread objects were signaled
case WAIT_OBJECT_0:
printf("All threads ended, cleaning up for application exit...\n");
break;
// An error occurred
default:
printf("WaitForMultipleObjects failed (%d)\n", GetLastError());
return 1;
}
// Close the events to clean up
CloseEvents();
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
// lpParam not used in this example.
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
printf("Thread %d waiting for write event...\n", GetCurrentThreadId());
dwWaitResult = WaitForSingleObject(
ghWriteEvent, // event handle
INFINITE); // indefinite wait
switch (dwWaitResult)
{
// Event object was signaled
case WAIT_OBJECT_0:
//
// TODO: Read from the shared buffer
//
printf("Thread %d reading from buffer\n",
GetCurrentThreadId());
break;
// An error occurred
default:
printf("Wait error (%d)\n", GetLastError());
return 0;
}
// Now that we are done reading the buffer, we could use another
// event to signal that this thread is no longer reading. This
// example simply uses the thread handle for synchronization (the
// handle is signaled when the thread terminates.)
printf("Thread %d exiting\n", GetCurrentThreadId());
return 1;
}
由於以上代碼中事件採用手動置位的方式,主線程寫完數據,再設置事件爲有信號狀態,然後所有的子線程都會同時運行,而非互斥運行————即一個線程寫,多個線程同時讀。