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: }