Using the Windows events object and thread related functions
// For WinXp as a target, change appropriately
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define NUMTHREADS 4
// Global...
DWORD WINAPI ThreadFunction(LPVOID);
HANDLE hGlobalWriteEvent;
HANDLE hReadEvents[NUMTHREADS];
// In the following 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.
// First, the master thread uses the CreateEvent function to create a manual-reset event object. The master thread 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. Then it 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.
void CreateEventsAndThreads(void)
{
HANDLE hThread;
DWORD i, IDThread;
// Create a manual-reset event object. The master thread sets this to nonsignaled when it writes to the shared buffer.
hGlobalWriteEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
TRUE, // initial state is signaled
L"WriteEvent" // object name
);
if (hGlobalWriteEvent == NULL)
printf("CreateEvent(): Creating a manual-reset event object failed (%d)\n", GetLastError());
else
printf("CreateEvent(): Creating a manual-reset event object is OK\n");
// Create multiple threads and an auto-reset event object for each thread. Each thread sets its event object to signaled when it is not reading from the shared buffer.
for(i = 0; i < NUMTHREADS; i++)
{
// Create the auto-reset event.
hReadEvents[i] = CreateEvent(
NULL, // no security attributes
FALSE, // auto-reset event
TRUE, // initial state is signaled
NULL); // object not named
if (hReadEvents[i] == NULL)
{
printf("CreateEvent(): Creating multiple threads failed (%d)\n", GetLastError());
}
else
printf("CreateEvent(): Creating multiple threads is OK\n");
hThread = CreateThread(NULL, 0,
ThreadFunction,
&hReadEvents[i], // pass event handle
0, &IDThread);
if (hThread == NULL)
printf("CreateThread() failed (%d)\n", GetLastError());
else
printf("CreateThread() is OK\n");
}
}
// 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 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, it sets hGlobalWriteEvent() and all the reader-thread
// events to signaled, enabling the reader threads to resume their read operations.
void WriteToBuffer(void)
{
DWORD dwWaitResult, i;
// Reset hGlobalWriteEvent to nonsignaled, to block readers.
if (!ResetEvent(hGlobalWriteEvent))
{
printf("ResetEvent() of the hGlobalWriteEvent to nonsignaled failed (%d)\n", GetLastError());
}
else
printf("ResetEvent() of the hGlobalWriteEvent to nonsignaled is OK\n");
// Wait for all reading threads to finish reading.
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)
{
// All read-event objects were signaled.
case WAIT_OBJECT_0:
{
// Write to the shared buffer.
printf("Writing to shared buffer...\n");
break;
}
// An error occurred.
default:
printf("Wait error: %d\n", GetLastError());
ExitProcess(0);
}
// Set hGlobalWriteEvent() to signaled.
if (!SetEvent(hGlobalWriteEvent))
{
printf("SetEvent() #1: hGlobalWriteEvent failed (%d)\n", GetLastError());
}
else
printf("SetEvent() #1: hGlobalWriteEvent is OK\n");
// Set all read events to signaled.
for(i = 0; i < NUMTHREADS; i++)
if (! SetEvent(hReadEvents[i]) )
{
printf("SetEvent() #2: Setting all read events to signaled failed (%d)\n", GetLastError());
}
else
printf("SetEvent() #2: Setting all read events to signaled is OK\n", GetLastError());
}
// 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.
DWORD WINAPI ThreadFunction(LPVOID lpParam)
{
DWORD dwWaitResult;
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)
{
// Both event objects were signaled.
case WAIT_OBJECT_0:
{
// Read from the shared buffer.
printf("Reading from the shared buffer...\n");
break;
}
// An error occurred.
default:
printf("Wait error: %d\n", GetLastError());
ExitThread(0);
}
// Set the read event to signaled.
if (!SetEvent(hEvents[0]))
printf("SetEvent() #3: Setting the read event to signaled failed (%d)\n", GetLastError());
else
printf("SetEvent() #3: Setting the read event to signaled is OK\n");
return dwWaitResult;
}
int main(void)
{
CreateEventsAndThreads();
WriteToBuffer();
return 0;
}
Output example:
CreateEvent(): Creating a manual-reset event object is OK
CreateEvent(): Creating multiple threads is OK
CreateThread() is OK
CreateEvent(): Creating multiple threads is OK
Reading from the shared buffer...
SetEvent() #3: Setting the read event to signaled is OK
CreateThread() is OK
Reading from the shared buffer...
CreateEvent(): Creating multiple threads is OK
SetEvent() #3: Setting the read event to signaled is OK
CreateThread() is OK
CreateEvent(): Creating multiple threads is OK
Reading from the shared buffer...
SetEvent() #3: Setting the read event to signaled is OK
CreateThread() is OK
ResetEvent() of the hGlobalWriteEvent to nonsignaled is OK
Reading from the shared buffer...
SetEvent() #3: Setting the read event to signaled is OK
Writing to shared buffer...
SetEvent() #1: hGlobalWriteEvent is OK
SetEvent() #2: Setting all read events to signaled is OK
SetEvent() #2: Setting all read events to signaled is OK
SetEvent() #2: Setting all read events to signaled is OK
SetEvent() #2: Setting all read events to signaled is OK
Press any key to continue . . .
Compiler: Visual C++ Express Edition 2005
Compiled on Platform: Windows XP Pro SP2
Target platform: none, just for learning and fun
Header file: Standard and Windows
Additional library: Windows Platform SDK
Additional project setting: Set project to be compiled as C
Project -> your_project_name Properties -> Configuration Properties -> C/C++ -> Advanced -> Compiled As: Compiled as C Code (/TC)
Other info: non-CLR or unmanaged
To do: Using the events object and thread related functions for thread synchronization
To show: The Windows process and thread related functions used in Win32 C programming