Event Objects

An event object is a synchronization object that allows one thread to notify another that an event has occurred. A thread uses CreateEvent to create an event object. The creating thread specifies the initial state of the object and whether it is a manual-reset or auto-reset event object. The creating thread can also specify a name for the event object. Threads in other processes can open a handle of an existing event object by specifying its name in a call to CreateEvent. For additional information about names for mutex and event objects, see Interprocess Synchronization.

Windows CE uses event objects to tell a thread when to perform its task or to indicate that a particular event has occurred. For example, a thread that writes to a buffer resets the event object to signaled when it has finished writing. By using an event object to notify the thread that its task is finished, the thread can immediately start performing other tasks.

A single thread can specify different event objects in several simultaneous overlapped operations. If this is the case, use one of the multiple-object wait functions to wait for the state of any one of the event objects to be signaled. You can also use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped input/output (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 Device I/O.

In the following code example, an application uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. The master thread uses the CreateEvent function to create a manual-reset event object. It sets the event object to nonsignaled when it is writing to the buffer and then resets the object to signaled when it has finished writing. The master thread then creates several reader threads and an auto-reset event object for each thread. Each reader thread sets its event object to signaled when it is not reading from the buffer.

#define NUMTHREADS 4 

HANDLE hGlobalWriteEvent; 

void CreateEventsAndThreads(void) 
{
      HANDLE hReadEvents[NUMTHREADS], hThread; 
      DWORD i, IDThread; 

      hGlobalWriteEvent = CreateEvent
         ( 
         NULL,                          // no security attributes
         TRUE,                          // manual-reset event
         TRUE,                          // initial state is signaled
         "WriteEvent"                   // object name
         ); 

      if (hGlobalWriteEvent == NULL) 
      { 
                                        // error exit
      }


      for(i = 1; i <= NUMTHREADS; i++) 
      {
         hReadEvents[i] = CreateEvent
            ( 
            NULL,                       // no security attributes
            FALSE,                      // auto-reset event
            TRUE,                       // initial state is signaled
            NULL);                      // object not named

         if (hReadEvents[i] == NULL) 
         {
                                        // error exit
         }

         hThread = CreateThread(NULL, 0, 
            (LPTHREAD_START_ROUTINE) ThreadFunction, 
            &hReadEvents[i],            // pass event handle
            0, &IDThread); 
         if (hThread == NULL) 
         {
                                        // error exit
         }
      }
}

In the following code example, before the master thread writes to the shared buffer, it uses the ResetEvent function to set the state of hGlobalWriteEvent, an application-defined global variable, to nonsignaled. This blocks the reader threads from starting a read operation. The master thread then uses the WaitForMultipleObjects function to wait for all reader threads to finish any current read operations. When WaitForMultipleObjects returns, the master thread can safely write to the buffer. After it has finished writing, it sets hGlobalWriteEvent and all the reader-thread events to signaled, which enables the reader threads to resume their read operations.

VOID WriteToBuffer(VOID) 
{
      DWORD dwWaitResult, i; 

 
      if (! ResetEvent(hGlobalWriteEvent) ) 
      { 
                                        // error exit
      } 


      dwWaitResult = WaitForMultipleObjects
         ( 
         NUMTHREADS,                    // number of handles in array
         hReadEvents,                   // array of read-event handles
         TRUE,                          // wait until all are signaled
         INFINITE);                     // indefinite wait

      switch (dwWaitResult) 
      {
         case WAIT_OBJECT_0: 
                                        // Write to the shared buffer.
               break;

                                        // An error occurred.
         default: 
               printf("Wait error: %d\n", GetLastError()); 
               ExitProcess(0); 
      } 

      if (! SetEvent(hGlobalWriteEvent) ) 
      {
                                        // error exit
      }

      for(i = 1; i <= NUMTHREADS; i++) 
         if (! SetEvent(hReadEvents[i]) ) 
         { 
                                        // error exit
         } 
}
 

In the following code example, before starting a read operation, each reader thread uses WaitForMultipleObjects to wait for the application-defined global variable, hGlobalWriteEvent, and its own read event to be signaled. When WaitForMultipleObjects returns, the reader thread's auto-reset event has been reset to nonsignaled. This blocks the master thread from writing to the buffer until the reader thread uses the SetEvent function to set the event's state back to signaled.

VOID ThreadFunction(LPVOID lpParam) 
{
      DWORD dwWaitResult, i;
      HANDLE hEvents[2]; 

      hEvents[0] = (HANDLE) *lpParam;   // thread's read event
      hEvents[1] = hGlobalWriteEvent; 

      dwWaitResult = WaitForMultipleObjects
         ( 
         2,                             // number of handles in array
         hEvents,                       // array of event handles
         TRUE,                          // wait till all are signaled
         INFINITE);                     // indefinite wait

      switch (dwWaitResult) 
      {

         case WAIT_OBJECT_0: 
               break; 

                                        // An error occurred.
         default: 
            printf("Wait error: %d\n", GetLastError()); 
            ExitThread(0); 
      }


      if (! SetEvent(hEvents[0]) ) 
      { 
                                        // error exit
      } 
}