Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Using Event Objects (Synchronization)

Applications can use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. For more information about the use of event objects in overlapped I/O operations, see Synchronization and Overlapped Input and Output.

The following example uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. First, the master thread uses the CreateEvent function to create a manual-reset event object whose initial state is nonsignaled. Then it creates several reader threads. The master thread performs a write operation and then sets the event object to the signaled state when it has finished writing.

Before starting a read operation, each reader thread uses WaitForSingleObject to wait for the manual-reset event object to be signaled. When WaitForSingleObject returns, this indicates that the main thread is ready for it to begin its read operation.

#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;
}


Feedback

Was this page helpful?

Additional resources