I started by defining some macros to make the code easier to read. The call to CreateEvent() takes some parameters that are simply TRUE or FALSE. When you are writing the code and reviewing the documentation these seem obvious, but later the code is not so easy to read. Then I created a typedef for a structure that I will pass into the thread. The reason for this is that it will allow me to write a single function but have it identify itself in my debug output because the data will be unique.
The thread is rather simple. It waits for the event to be signaled and then outputs information about why the call to WaitForSingleObject() returned. Note that the thread doesn’t even have a loop, once the wait returns, the thread returns and exits.
Then the main function exersises the event by creating the event, starting the threads and signaling the event. It runs through the following tests first for auto reset events, and then for manual reset events:
You will notice in the code that I added calls to Sleep() after starting the threads and before calling SetEvent() or PulseEvent(). This is necessary to ensure that the threads are waiting for the event before signaling the event. See my comments at the end about why I set the Sleep() timeouts the way that I did.
int wmain(int argc, _TCHAR* argv[])
{
ThreadData ThreadData1;
ThreadData ThreadData2;
HANDLE Event;
RETAILMSG( 1, (TEXT("Starting Thread Test\n")));
Event = CreateEvent(NULL, AUTORESET, START_NONSIGNALED, NULL );
ThreadData1.Event = Event;
ThreadData1.ThreadID = TEXT("Thread1");
ThreadData1.Timeout = 10000;
ThreadData2.Event = Event;
ThreadData2.ThreadID = TEXT("Thread2");
ThreadData2.Timeout = 10000;
RETAILMSG( 1, (TEXT("Start Auto Reset Tests\n")));
RETAILMSG( 1, (TEXT("\tTesting one thread\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
Sleep(500);
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
RETAILMSG( 1, (TEXT("\tTesting one thread with timeout\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread, &ThreadData1, 0, NULL );
Sleep( 1500 );
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
RETAILMSG( 1, (TEXT("\tTesting two threads with SetEvent\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
ThreadData2.hThread = CreateThread(NULL, 0, EventThread,&ThreadData2, 0, NULL );
Sleep(5000);
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
WaitForSingleObject( ThreadData2.hThread, INFINITE );
CloseHandle( ThreadData2.hThread );
RETAILMSG( 1, (TEXT("\tTesting two threads with PulseEvent\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
ThreadData2.hThread = CreateThread(NULL, 0, EventThread,&ThreadData2, 0, NULL );
Sleep(5000);
PulseEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
WaitForSingleObject( ThreadData2.hThread, INFINITE );
CloseHandle( ThreadData2.hThread );
CloseHandle(Event);
RETAILMSG( 1, (TEXT("Start Manual Reset Tests\n")));
Event = CreateEvent(NULL, MANUALRESET, START_NONSIGNALED, NULL );
ThreadData1.Event = Event;
ThreadData2.Event = Event;
RETAILMSG( 1, (TEXT("\tTesting one thread\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
Sleep(500);
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
ResetEvent(Event);
RETAILMSG( 1, (TEXT("\tTesting one thread with timeout\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread, &ThreadData1, 0, NULL );
Sleep( 1500 );
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
ResetEvent(Event);
RETAILMSG( 1, (TEXT("\tTesting two threads with SetEvent\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
ThreadData2.hThread = CreateThread(NULL, 0, EventThread,&ThreadData2, 0, NULL );
Sleep(500);
SetEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
WaitForSingleObject( ThreadData2.hThread, INFINITE );
CloseHandle( ThreadData2.hThread );
ResetEvent(Event);
RETAILMSG( 1, (TEXT("\tTesting two threads with PulseEvent\n")));
ThreadData1.hThread = CreateThread(NULL, 0, EventThread,&ThreadData1, 0, NULL );
ThreadData2.hThread = CreateThread(NULL, 0, EventThread,&ThreadData2, 0, NULL );
Sleep(500);
PulseEvent( Event );
WaitForSingleObject( ThreadData1.hThread, INFINITE );
CloseHandle( ThreadData1.hThread );
WaitForSingleObject( ThreadData2.hThread, INFINITE );
CloseHandle( ThreadData2.hThread );
ResetEvent(Event);
CloseHandle(Event);
return 0;
}
I have to admit that I tested this using Visual Studio 2005 and the Pocket PC 2003 emulator. There appear to be some side effects of doing so, primarily that nothing worked as it should have. I guess that is why I don’t use the emulator much for testing, but I didn’t have a device handy. So you might notice some odd timeouts, but they seem to have been necessary on the debugger to allow threads to run and get to the point were they waited for the event.