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