Version: 8.3.0
YACS::BASES::AlternateThreadPT Class Referenceabstract

This class provides a mechanism to run two threads alternately. More...

#include <AlternateThreadPT.hxx>

Collaboration diagram for YACS::BASES::AlternateThreadPT:

Public Types

enum  ThreadStatus { UNEXISTING, NORMAL_CYCLE, TERMINATION_REQUESTED, READY_TO_JOIN }
 

Public Member Functions

 AlternateThreadPT ()
 
virtual ~AlternateThreadPT ()
 
void start ()
 Create and launch the slave thread. More...
 
virtual void signalSlaveAndWait ()
 Block the master thread and release the slave thread. More...
 
void terminateSlaveThread ()
 Terminate the slave thread. More...
 
virtual void signalMasterAndWait ()
 Block the slave thread and release the master thread. More...
 
bool isTerminationRequested () const
 Return true if the master requested the slave thread termination. More...
 
ThreadStatus getThreadStatus () const
 Return the thread status. More...
 

Protected Member Functions

virtual void run ()=0
 This method must be implemented in subclasses and will be run in the slave thread. More...
 

Private Member Functions

void signalAndWait ()
 

Static Private Member Functions

static void * runThread (void *instance)
 
static void threadCleanupFct (void *instance)
 

Private Attributes

pthread_t _threadId
 
ThreadStatus _threadStatus
 
pthread_cond_t _pingPongCond
 
pthread_mutex_t _pingPongMutex
 

Detailed Description

This class provides a mechanism to run two threads alternately.

Alternate threads can be necessary when two pieces of code must run alternately and communicate but are difficult or impossible to synchronize explicitly (e.g. asynchronous algorithms in optimizer loop). This class guarantees that the two threads NEVER run concurrently, so no lock mechanism is necessary when sharing data between them.

The two threads are called "master thread" and "slave thread". The master thread is the one that calls the method start() and that will continue to run after the destruction of this object. The slave thread is created when the method start() is called. It will run the code in the method run() and will be destroyed when the master thread calls terminateSlaveThread() or at the destruction of this object.

When the master thread calls start(), it will block and the slave thread will begin to execute the code in the method run(). The two threads can then alternate by calling the method signalMasterAndWait() (in the slave thread) and signalSlaveAndWait() (in the master thread). Finally, the master thread must call terminateSlaveThread() to terminate the slave thread. There is no explicit mechanism for the slave thread to request its own termination, but this can be done with an external flag (see the pool object in OptimizerLoop for instance).

This class is purely virtual. Subclasses must implement the run() method that will be executed in the slave thread.

Definition at line 55 of file AlternateThreadPT.hxx.

Member Enumeration Documentation

Enumerator
UNEXISTING 
NORMAL_CYCLE 
TERMINATION_REQUESTED 
READY_TO_JOIN 

Definition at line 58 of file AlternateThreadPT.hxx.

Constructor & Destructor Documentation

AlternateThreadPT::AlternateThreadPT ( )

Definition at line 31 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, and YASSERT.

33 {
34  YASSERT(pthread_cond_init(&_pingPongCond, NULL) == 0)
35  YASSERT(pthread_mutex_init(&_pingPongMutex, NULL) == 0)
36 }
AlternateThreadPT::~AlternateThreadPT ( )
virtual

Definition at line 38 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, terminateSlaveThread(), and YASSERT.

39 {
40  try {
42  YASSERT(pthread_mutex_destroy(&_pingPongMutex) == 0)
43  YASSERT(pthread_cond_destroy(&_pingPongCond) == 0)
44  } catch (const exception & e) {
45  cerr << "Exception happened in AlternateThreadPT destructor: " << e.what() << endl;
46  } catch (...) {
47  cerr << "Unknown exception happened in AlternateThreadPT destructor." << endl;
48  }
49 }

Member Function Documentation

AlternateThreadPT::ThreadStatus AlternateThreadPT::getThreadStatus ( ) const

Return the thread status.

Definition at line 134 of file AlternateThreadPT.cxx.

References _threadStatus.

135 {
136  return _threadStatus;
137 }
bool AlternateThreadPT::isTerminationRequested ( ) const

Return true if the master requested the slave thread termination.

Definition at line 129 of file AlternateThreadPT.cxx.

References _threadStatus, and TERMINATION_REQUESTED.

130 {
132 }
virtual void YACS::BASES::AlternateThreadPT::run ( )
protectedpure virtual

This method must be implemented in subclasses and will be run in the slave thread.

The slave thread must call signalMasterAndWait() when necessary to give the control back to the master thread. When returning from this method, the slave thread MUST check for an eventual termination request (with the method isTerminationRequested()). If the termination is requested, the slave thread must perform any necessary cleanup and finish as soon as possible.

Referenced by runThread().

void * AlternateThreadPT::runThread ( void *  instance)
staticprivate

Definition at line 139 of file AlternateThreadPT.cxx.

References _pingPongMutex, _threadStatus, DEBTRACE, NORMAL_CYCLE, run(), threadCleanupFct(), and YASSERT.

Referenced by start().

140 {
141  try {
142  AlternateThreadPT * instanceCst = (AlternateThreadPT *)instance;
143  YASSERT(pthread_mutex_lock(&instanceCst->_pingPongMutex) == 0)
144  DEBTRACE("Slave thread is now running")
145  instanceCst->_threadStatus = NORMAL_CYCLE;
146  pthread_cleanup_push(threadCleanupFct, instance);
147  instanceCst->run();
148  pthread_cleanup_pop(1);
149  } catch (const exception & e) {
150  cerr << "Unrecoverable error: an exception was caught in AlternateThread "
151  "(exceptions should normally be caught before getting here). "
152  "Exception type is: " << typeid(e).name() << ", message is: " <<
153  e.what() << endl;
154  threadCleanupFct(instance);
155  }
156  // We can't catch (...) here because it causes problems with thread cancellation, at least
157  // with gcc 4.1.2 and older. With newer versions it should be possible to do something like
158  // catch (abi::__forced_unwind e) { throw; }. See
159  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28145 for details.
160  // The problem is that no exception should get out of the thread scope without being caught
161  // (otherwise the program aborts). So for now the user has to take care of catching all
162  // exceptions, but he cannot use catch (...).
163  return NULL;
164 }
void AlternateThreadPT::signalAndWait ( )
private

Definition at line 122 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, _threadStatus, NORMAL_CYCLE, TERMINATION_REQUESTED, and YASSERT.

Referenced by signalMasterAndWait(), and signalSlaveAndWait().

123 {
125  YASSERT(pthread_cond_signal(&_pingPongCond) == 0)
126  YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
127 }
void AlternateThreadPT::signalMasterAndWait ( )
virtual

Block the slave thread and release the master thread.

Definition at line 114 of file AlternateThreadPT.cxx.

References _threadId, DEBTRACE, signalAndWait(), and YASSERT.

115 {
116  YASSERT(pthread_equal(pthread_self(), _threadId))
117  DEBTRACE("Slave signaling master and waiting");
118  signalAndWait();
119  DEBTRACE("Slave running again");
120 }
void AlternateThreadPT::signalSlaveAndWait ( )
virtual

Block the master thread and release the slave thread.

Definition at line 106 of file AlternateThreadPT.cxx.

References _threadId, DEBTRACE, signalAndWait(), and YASSERT.

Referenced by terminateSlaveThread().

107 {
108  YASSERT(!pthread_equal(pthread_self(), _threadId))
109  DEBTRACE("Master signaling slave and waiting");
110  signalAndWait();
111  DEBTRACE("Master running again");
112 }
void AlternateThreadPT::start ( )

Create and launch the slave thread.

This method must not be called by the slave thread or if a slave thread is already running.

Definition at line 51 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, _threadId, _threadStatus, DEBTRACE, runThread(), UNEXISTING, and YASSERT.

52 {
53  // This method must not be called if a slave thread is running
55 
56  YASSERT(pthread_mutex_lock(&_pingPongMutex) == 0)
57  DEBTRACE("Starting thread")
58  YASSERT(pthread_create(&_threadId, 0, runThread, this) == 0)
59  DEBTRACE("Master waiting for slave")
60  YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
61  DEBTRACE("Master running again")
62 }
void AlternateThreadPT::terminateSlaveThread ( )

Terminate the slave thread.

Definition at line 64 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, _threadId, _threadStatus, DEBTRACE, NORMAL_CYCLE, READY_TO_JOIN, signalSlaveAndWait(), TERMINATION_REQUESTED, UNEXISTING, and YASSERT.

Referenced by ~AlternateThreadPT().

65 {
66  // This method must not be called by the slave thread
67  YASSERT(_threadStatus == UNEXISTING || !pthread_equal(pthread_self(), _threadId))
68 
69  switch (_threadStatus) {
70  case UNEXISTING:
71  return;
72  case READY_TO_JOIN:
73  break;
74  case NORMAL_CYCLE:
75  {
76  // First try to signal the slave thread to end properly
77  DEBTRACE("Master is trying to terminate slave by signaling error")
78  _threadStatus = TERMINATION_REQUESTED;
80 
81  if (_threadStatus != READY_TO_JOIN) {
82  // Try to cancel the thread
83  cerr << "Warning: Slave thread in AlternateThread did not end properly. "
84  "Thread will be canceled." << endl;
85  YASSERT(pthread_cancel(_threadId) == 0)
86  YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
87 
88  if (_threadStatus != READY_TO_JOIN) {
89  // If cancel failed, we can do nothing more, throw an exception
90  YASSERT(false);
91  }
92  }
93  break;
94  }
95  default:
96  YASSERT(false)
97  }
98 
99  // Finally join the thread
100  YASSERT(pthread_mutex_unlock(&_pingPongMutex) == 0)
101  YASSERT(pthread_join(_threadId, NULL) == 0)
102  _threadStatus = UNEXISTING;
103  DEBTRACE("AlternateThread terminated")
104 }
void AlternateThreadPT::threadCleanupFct ( void *  instance)
staticprivate

Definition at line 166 of file AlternateThreadPT.cxx.

References _pingPongCond, _pingPongMutex, _threadStatus, DEBTRACE, and READY_TO_JOIN.

Referenced by runThread().

167 {
168  // Beware of not throwing exceptions in this method
169  DEBTRACE("Cleaning up slave thread")
170  AlternateThreadPT * instanceCst = (AlternateThreadPT *)instance;
171  instanceCst->_threadStatus = READY_TO_JOIN;
172  pthread_cond_signal(&instanceCst->_pingPongCond);
173  pthread_mutex_unlock(&instanceCst->_pingPongMutex);
174 }

Member Data Documentation

pthread_cond_t YACS::BASES::AlternateThreadPT::_pingPongCond
private
pthread_mutex_t YACS::BASES::AlternateThreadPT::_pingPongMutex
private
pthread_t YACS::BASES::AlternateThreadPT::_threadId
private
ThreadStatus YACS::BASES::AlternateThreadPT::_threadStatus
private

The documentation for this class was generated from the following files: