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

 

 

C and C++ Programming Resources | C & C++ Code Example Index