例子来自MSDN。
整个过程应该是这样的:一些线程要去读取一个缓冲区,但是要在对该缓冲区完成一些操作后才能让其读取,而且完成后要通知这些线程。这里的通知当然就是事件了(如果说最底层的原理,不如说是一个无限循环)。在创建这些线程的时候,线程就被赋予一个要求,必须等到对该缓冲区的标识变为可行的时候才能执行,这样的话就完成了对线程读取的控制。对缓冲区的操作线程完成后,就会将标识变为可行,此后,那些线程的无限循环又执行到检查标识时,就会通过检查,这样的表现就是,对缓冲区的操作完成后通知读取缓冲区的操作,虽然实际上不是这样的,但结果和表现是这样的,这就是事件。
源代码#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 nonsignaled state when it finishes writing to a // shared buffer. // 事件本事就是一个handle,可以通过它获得某个标识 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); } void main() { 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; } // Close the events to clean up CloseEvents(); } DWORD WINAPI ThreadProc(LPVOID 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; }