Click here to Skip to main content
15,884,425 members
Articles / Programming Languages / C++
Article

VC++ Thread Synchronizatrion Using Events

Rate me:
Please Sign up or sign in to vote.
2.88/5 (8 votes)
17 Dec 2006CPOL3 min read 47.2K   17   2
This article demonstrates how to synchronize two threads using events.

Introduction

Interesting and challenging as it sounds, thread synchronization is still a major ouch! for an intermediate developer. This article, although not an expert insight into thread programming, serves as a primer for developers seeking to synchronize threads using events. There are many different synchronization objects (mutexes, semaphores, Critical Sections etc.) that can be used, but for the specific case that is going to be discussed, I think events serve the best purpose for synchronization. But as always, I am welcome to suggestions!

Understanding this article requires a basic understanding of multi-threaded programming.

The case in question: A main thread spawns two threads. It is required to execute each thread alternately, i.e., first Thread 1, then Thread 2, then again Thread 1, Thread 2 etc.

A Few Basics

The Event object is created using the CreateEvent function. The event can be either in a signaled or non-signaled state. Signaled means that the Event has released some waiting thread. Non-signaled means that all threads waiting for this event need to wait for it to become signaled. The SetEvent and ResetEvent functions can be used for putting the Event in the Signaled and Non-Signaled states, respectively. Basically, an event signifies to the process that something has happened. The waiting threads can then act accordingly once this event has occurred.

Let the Coding Commence

#include <windows.h>

#include <iostream.h>

/*************GLOBALS************/

HANDLE hThread1 , hThread2;
HANDLE hEvent1 , hEvent2;
int  g_nShared = 0; /* Global variable which is 
        going to be accessed by both Threads */

DWORD WINAPI Thread1(LPVOID lParam)
{
 while(1)
 {
  WaitForSingleObject(hEvent2,INFINITE);   
  ResetEvent(hEvent2);
  cout << "Thread1()::g_nShared = " << ++g_nShared << endl;
  SetEvent(hEvent1);   
 }
 return 0;
}

DWORD WINAPI Thread2(LPVOID lParam)
{
 while(1)
 {
  WaitForSingleObject(hEvent1,INFINITE);  
  ResetEvent(hEvent1);
  cout << "Thread2()::g_nShared = " << ++g_nShared << endl;
  SetEvent(hEvent2);  
 }
 return 0;
}

void main()
{
 // The Events which synchronize the 2 threads

 hEvent1 = CreateEvent(NULL,TRUE,FALSE,"Event1");
 hEvent2 = CreateEvent(NULL,TRUE,FALSE,"Event2");
 
 // Signal both the Events...so that they're up for grabs before 

 // the threads are born!!

 SetEvent(hEvent1); 
 SetEvent(hEvent2);
 
 // The Threads are Brought to Life !

 hThread1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Thread1,NULL,0,0);
 hThread2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Thread2,NULL,0,0); 
 
 while(1); // Don't let the Main Thread Die 

}

Explanation

Since there are two threads, we need to have two event objects to synchronize them, i.e., we need to make one thread wait till the other thread has finished executing a cycle. Each thread waits on an event object to be signaled. The other thread changes the state of this event object to signaled once it has completed executing one of its cycles.

The program starts with the main() function creating the two event objects, which are manual in nature. Hence, they need to be first put in the Signaled state before the threads are created. If you create and signal the events after creating the threads, then the program will wait indefinitely without any output on the console screen.

After this, the threads are spawned using the CreateThread function.

Thread1 executes first, since it is created first. It waits in the while loop for the hEvent2 object to get signaled. But, since hEvent2 is already signaled for the first execution of the loop, the next line is executed immediately. The next line puts the hEvent2 object in the non-signaled state by calling the function ResetEvent(). It then changes the value of the shared global g_nShared and then signals the hEvent1 object. Although this statement has no effect in the first execution of the loop, it plays an important role later. The point of execution returns to the beginning of the while loop where Thread 1 waits for the hEvent2 object to be signaled. This will get signaled by Thread 2 later. So, till that time, Thread 1 will have to wait.

Thread 2 is then executed since the hEvent1 object that it is waiting for is already signaled. Similar to Thread 1, it non-signals the hEvent1 object, changes the value of g_nShared, and then signals the hEvent2 object which causes Thread 1 to get executed again and Thread 2 to wait on the hEvent1 object to get signaled. This alternating cycles of loops of Thread 1 and Thread 2 continues till the program is terminated by the user.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
India India
Neeraj currently works as a developer for a mulinational IT company.
With experience of nearly 3 years in VC++ development (although his friends would not agree about the last 1-1.5 years Smile | :) )
Areas of interest mainly include the most difficult of topics in VC++ i.e. Thread synchronizing, as this forms a big part of his current job.

Comments and Discussions

 
QuestionDo you really know event and thread mechanism? Pin
Member 118150395-Jul-15 12:28
Member 118150395-Jul-15 12:28 
Questionwhat if createthread is done one 2 different processes at the same time???? Pin
prashu10015-Oct-10 20:31
prashu10015-Oct-10 20:31 
DeadLock!! CriticalSection should be used in case of events.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.