Earlier I wrote about using Events in Windows CE (see Windows CE: Synchronization Objects – Events and Windows CE: Event Test Code) but I didn’t discuss event data.
Events can have data associated with them so that one thread can pass a small piece of data to another thread. This is accomplished by calling SetEventData() and GetEventData(). The data is a DWORD, although that means that it can be a pointer to data. Of course the pointer only works if both threads are in the same process, but either way it is probably risky.
The catch to using SetEventData() and GetEventData() is that the data can be overwritten between the call to SetEvent() in one thread and the other thread being unblocked. To see this, the following code has a thread that increments a counter from 0 to 100 and calls SetEventData() with each count. Another thread waits for the event and then outputs the data.
The code:
static DWORD WINAPI EventDataThread( LPVOID lpParam)
{
      DWORD WFSO_Ret;
      ThreadData *pData = (ThreadData *)lpParam;
      DWORD Done = FALSE;
     
      while( !Done )
      {
            WFSO_Ret = WaitForSingleObject( pData->Event, pData->Timeout);
 
            if( WFSO_Ret == WAIT_TIMEOUT )
            {
                  RETAILMSG( 1, (TEXT("\t\t%s timeout\n"), pData->ThreadID ));
                  Done = TRUE;
            }
            else if ( WFSO_Ret == WAIT_OBJECT_0 )
                  RETAILMSG( 1, (TEXT("\t\t%s event signaled Data %d\n"), pData->ThreadID, GetEventData(pData->Event) ));
            else
                  RETAILMSG( 1, (TEXT("\t\t%s error %d\n"), pData->ThreadID, GetLastError() ));
      }
      return TRUE;
}
 
// From another thread, for an explanation of the data see Windows CE: Event Test Code:
 
      Event = CreateEvent(NULL, AUTORESET, START_NONSIGNALED, NULL );
      ThreadData1.Event = Event;
      ThreadData1.hThread = CreateThread(NULL, 0, EventDataThread,&ThreadData1, 0, NULL );
      Sleep(50);
      for( int i = 0; i < 101; i++)
      {
            SetEventData( ThreadData1.Event, i );
            SetEvent( ThreadData1.Event );
      }
      WaitForSingleObject( ThreadData1.hThread, INFINITE );
      CloseHandle( ThreadData1.hThread );
 
                CloseHandle( Event );
 
 The code looks okay, but the output is:
              Thread1 event signaled Data 100
              Thread1 event signaled Data 100
              Thread1 timeout
 
Which doesn’t at all show the EventDataThread() responding to the event, or displaying the data. Not only that but it outputs the counter value 100 twice. What is going on here? The threads are starving each other, so the thread that is setting the event and data is keeping EventDataThread() from running. Then EventDataThread() runs on the 99 event, but the data changes before it reads the data. Let’s try to fix this by giving the two threads some work to do, in this case let’s have them call Sleep() to use up some time. By simply adding a Sleep(5); to both theads within their loops, the output changes to:
              Thread1 event signaled Data 0
              Thread1 event signaled Data 2
              Thread1 event signaled Data 5
              Thread1 event signaled Data 8
              Thread1 event signaled Data 11
              Thread1 event signaled Data 14
              Thread1 event signaled Data 16
              Thread1 event signaled Data 19
              Thread1 event signaled Data 22
              Thread1 event signaled Data 25
              Thread1 event signaled Data 27
              Thread1 event signaled Data 30
              Thread1 event signaled Data 33
              Thread1 event signaled Data 36
              Thread1 event signaled Data 39
              Thread1 event signaled Data 41
              Thread1 event signaled Data 44
              Thread1 event signaled Data 47
              Thread1 event signaled Data 50
              Thread1 event signaled Data 53
              Thread1 event signaled Data 56
              Thread1 event signaled Data 59
              Thread1 event signaled Data 62
              Thread1 event signaled Data 65
              Thread1 event signaled Data 68
              Thread1 event signaled Data 71
              Thread1 event signaled Data 74
              Thread1 event signaled Data 77
              Thread1 event signaled Data 80
              Thread1 event signaled Data 83
              Thread1 event signaled Data 86
              Thread1 event signaled Data 89
              Thread1 event signaled Data 92
              Thread1 event signaled Data 95
              Thread1 event signaled Data 98
              Thread1 event signaled Data 100
              Thread1 timeout
 
Which is acceptable if what we are doing is updating a progress bar, but not acceptable if we need to actually handle each piece of data. I will leave that problem up to you to solve, but I think that it will involve thread priorities and possibly use of more synchronization objects – followed by a lot of testing. There are probably better ways to pass the data if it is that important, like message queues.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved