ManualResetEvent for C++

I have the luxury of working in a development house where I’m not stuck to one technology stack. And soon after the C# ManualResetEvent and the Java ManualResetEvent equivalent I had to get busy with one for C++.

The requirement was for a thread interruption mechanism when certain events occurred. After a quick search I found Conditional Variables in C++. It is a synchronization device that allows threads to suspend execution and relinquish the processors until some predicate on shared data is satisfied. The basic operations on conditions are: signal the condition (when the predicate becomes true), and wait for the condition, suspending the thread execution until another thread signals the condition (https://www.sourceware.org/pthreads-win32/manual/pthread_cond_init.html).


Download source

https://github.com/roshfsk/CPP-ManualResetEvent


ManualResetEvent.cpp
1:  /*  
2:   * ManualResetEvent.cpp  
3:   *  
4:   * Created on: Feb 15, 2016  
5:   *   Author: RoshanF  
6:   */  
7:  #include   
8:  ManualResetEvent::ManualResetEvent() {  
9:      // TODO Auto-generated constructor stub  
10:  }  
11:  ManualResetEvent::~ManualResetEvent() {  
12:      // TODO Auto-generated destructor stub  
13:  }  
14:  void ManualResetEvent::init(struct MREStruct *ev) {  
15:    pthread_mutex_init(&ev->mutex, 0);  
16:    pthread_cond_init(&ev->cond, 0);  
17:    ev->triggered = false;  
18:  }  
19:  void ManualResetEvent::trigger(struct MREStruct *ev) {  
20:    pthread_mutex_lock(&ev->mutex);  
21:    ev->triggered = true;  
22:    pthread_cond_broadcast(&ev->cond);  
23:    pthread_mutex_unlock(&ev->mutex);  
24:  }  
25:  void ManualResetEvent::reset(struct MREStruct *ev) {  
26:    pthread_mutex_lock(&ev->mutex);  
27:    ev->triggered = false;  
28:    pthread_mutex_unlock(&ev->mutex);  
29:  }  
30:  void ManualResetEvent::wait(struct MREStruct *ev) {  
31:     pthread_mutex_lock(&ev->mutex);  
32:     while (!ev->triggered)  
33:       pthread_cond_wait(&ev->cond, &ev->mutex);  
34:     pthread_mutex_unlock(&ev->mutex);  
35:  }  
DemoMain.cpp

This class contains modules to demonstrate the functionality of the ManualResetEvent wrapper and the basic thread implementation with a sleep function.

The Counter Thread

The counter thread simply increments a count variable periodically (say count++ every 2 seconds). It also calls the set() trigger of the ManualResetEvent handle.

The Sleeper Thread

This thread is used to show in comparison, how polling and interrupts in the form of ManualResetEvents provide differentiation for applications. This thread periodically prints the value of the count variable. The polling does not care if there has been a change or not, it just keeps on doing its job.

The ManualResetEvent Thread

This thread uses the ManualResetEvent wrapper to get interrupts from the Counter Thread, every time an update is done. Once the interrupt wakes the thread it prints the counter value and resets its handle, allowing the thread to go back to sleep.

1:  /*  
2:   * DemoMain.cpp  
3:   *  
4:   * Created on: Feb 15, 2016  
5:   *   Author: RoshanF  
6:   */  
7:  #include "DemoMain.h"  
8:  using namespace std;  
9:  static int counter;  
10:  static ManualResetEvent * mreHandle;  
11:  pthread_mutex_t m_MREventLock;  
12:  DemoMain::DemoMain() {  
13:      // TODO Auto-generated constructor stub  
14:      cout << "DemoMain constructed" <init(&mreHandle->eventStruct);  
22:      counter = 0;  
23:      int rc;  
24:      rc = pthread_create(&m_CounterThread, NULL, CounterThread, (void *)0);  
25:      if (rc) {  
26:          cout << "Error:unable to create CounterThread," << rc << endl;  
27:          exit(-1);  
28:      }  
29:      rc = pthread_create(&m_SleeperThread, NULL, SleeperThread, (void *)1);  
30:      if (rc) {  
31:          cout << "Error:unable to create SleeperThread," << rc << endl;  
32:          exit(-1);  
33:      }  
34:      rc = pthread_create(&m_ManualResetEventThread, NULL, ManualResetEventThread, (void *)2);  
35:      if (rc) {  
36:          cout << "Error:unable to create thread," << rc << endl;  
37:          exit(-1);  
38:      }  
39:  }  
40:  DemoMain::~DemoMain() {  
41:      // TODO Auto-generated destructor stub  
42:  }  
43:  #define NUM_THREADS   5  
44:  int main ()  
45:  {  
46:      cout << "App started" <trigger(&mreHandle->eventStruct);  
56:          pthread_mutex_unlock(&m_MREventLock);  
57:          cout << "CounterThread counter update: " << counter << endl;  
58:      }  
59:      pthread_exit(NULL);  
60:  }  
61:  void * DemoMain::SleeperThread(void * obj) {  
62:      while(true) {  
63:          usleep(1000 * 100 * 5); // 0.5 seconds  
64:          cout << "SleeperThread Counter" << counter <wait(&mreHandle->eventStruct);  
71:          //lock  
72:          pthread_mutex_lock(&m_MREventLock);  
73:          cout << "ManualResetEventThread Counter" << counter <reset(&mreHandle->eventStruct);  
75:          pthread_mutex_unlock(&m_MREventLock);  
76:          //unlock  
77:      }  
78:      pthread_exit(NULL);  
79:  }  

Leave a comment