Windows Thread Synchronization 19

 

 

 

 

 

Using Event Objects Program Example

 

Applications can use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. The following example 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 whose initial state is nonsignaled. Then it creates several reader threads. The master thread performs a write operation and then sets the event object to the signaled state when it has finished writing. Before starting a read operation, each reader thread uses WaitForSingleObject() to wait for the manual-reset event object to be signaled. When WaitForSingleObject() returns, this indicates that the main thread is ready for it to begin its read operation.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

 

Using Event Objects Program Example - creating new Win32 console application Visual C++ project

 

Then, add the source file and give it a suitable name.

 

Using Event Objects Program Example: Adding new C++ source file for the C++ source code

 

Next, add the following source code.

 

#include <windows.h>

#include <stdio.h>

 

#define THREADCOUNT 4

 

HANDLE ghWriteEvent;

HANDLE ghThreads[THREADCOUNT];

 

DWORD WINAPI ThreadProc(LPVOID);

 

void CreateEventsAndThreads(void)

{

    int i;

    DWORD dwThreadID;

 

    // Create a manual-reset event object. The write thread sets this

    // object to the nonsignaled state when it finishes writing to a shared buffer.

    ghWriteEvent = CreateEvent(

        NULL,          // default security attributes

        TRUE,          // manual-reset event

        FALSE,         // initial state is nonsignaled

        L"MyWriteEventGedik"  // object name

        );

 

    if (ghWriteEvent == NULL)

    {

        wprintf(L"CreateEvent() failed, error %d\n", GetLastError());

        return;

    }

      else

            wprintf(L"CreateEvent() is OK...\n");

 

    // Create multiple threads to read from the buffer.

    for(i = 0; i < THREADCOUNT; i++)

    {

        // TODO: More complex scenarios may require use of a parameter

        //   to the thread procedure, such as an event per thread to 

        //   be used for synchronization.

        ghThreads[i] = CreateThread(

            NULL,              // default security

            0,                 // default stack size

            ThreadProc,        // name of the thread function

            NULL,              // no thread parameters

            0,                 // default startup flags

            &dwThreadID);

 

        if (ghThreads[i] == NULL)

        {

            wprintf(L"CreateThread() failed, error %d\n", GetLastError());

            return;

        }

            else

                  wprintf(L"CreateThread() for thread #%d is OK!\n", i);

    }

}

 

void WriteToBuffer(void)

{

    // TODO: Write to the shared buffer.   

    wprintf(L"Main thread writing to the shared buffer...\n");

    // Set ghWriteEvent to signaled

    if (! SetEvent(ghWriteEvent) )

    {

        wprintf(L"\nSetEvent() failed, error %d\n", GetLastError());

        return;

    }

      else

            wprintf(L"\nSetEvent() is OK!\n");

}

 

void CloseEvents()

{

    // Close all event handles (currently, only one global handle).   

    if(CloseHandle(ghWriteEvent) != 0)

            wprintf(L"Closing the ghWriteEvent's handle is OK\n");

      else

            wprintf(L"Fail to close ghWriteEvent's handle, error %d\n", GetLastError());

}

 

void wmain()

{

    DWORD dwWaitResult;

 

    wprintf(L"The main() process started...\n");

    wprintf(L" With thread #%d\n", GetCurrentThreadId());

 

    // TODO: Create the shared buffer

    // Create events and THREADCOUNT threads to read from the buffer

    CreateEventsAndThreads();

 

    // At this point, the reader threads have started and are most

    // likely waiting for the global event to be signaled. However,

    // it is safe to write to the buffer because the event is a

    // manual-reset event.   

    WriteToBuffer();

 

    wprintf(L"The main thread waiting for threads to exit...\n");

 

    // The handle for each thread is signaled when the thread is terminated.

    dwWaitResult = WaitForMultipleObjects(

        THREADCOUNT,   // number of handles in array

        ghThreads,     // array of thread handles

        TRUE,          // wait until all are signaled

        INFINITE);

 

    switch (dwWaitResult)

    {

        // All thread objects were signaled

        case WAIT_OBJECT_0:

            wprintf(L"All threads ended, cleaning up for application exit...\n");

            break;

        // An error occurred

        default:

            wprintf(L"WaitForMultipleObjects failed (%d)\n", GetLastError());

            return;

    }

           

    // Close the events to clean up

    CloseEvents();

}

 

DWORD WINAPI ThreadProc(LPVOID lpParam)

{

    DWORD dwWaitResult;

 

    wprintf(L"Thread %d waiting for the write event...\n", GetCurrentThreadId());

   

    dwWaitResult = WaitForSingleObject(

        ghWriteEvent, // event handle

        INFINITE);    // indefinite wait

 

    switch (dwWaitResult)

    {

        // Event object was signaled

        case WAIT_OBJECT_0:

            // TODO: Read from the shared buffer

            wprintf(L"Thread %d reading from buffer...\n", GetCurrentThreadId());

            break;

        // An error occurred

        default:

            wprintf(L"WaitForSingleObject() error %d\n", GetLastError());

            return 0;

    }

 

    // Now that we are done reading the buffer, we could use another

    // event to signal that this thread is no longer reading. This

    // example simply uses the thread handle for synchronization (the

    // handle is signaled when the thread terminates.)

    wprintf(L"Thread %d exiting...\n", GetCurrentThreadId());

    return 1;

}

 

Build and run the project. The following screenshot is a sample output.

 

 

Using Event Objects Program Example: A sample console program output

 

 

 

 

< Thread Synchronization 18 | Thread Synchronization Programming | Win32 Programming | Thread Synchronization 20 >