libfoedus-core
FOEDUS Core Library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
foedus::thread::ConditionVariable Class Referencefinal

An analogue of pthread's condition variable and std::condition_variable to avoid glibc's bug in pthread_cond_broadcast/signal (thus in notify_all/one in turn). More...

Detailed Description

An analogue of pthread's condition variable and std::condition_variable to avoid glibc's bug in pthread_cond_broadcast/signal (thus in notify_all/one in turn).

The whole purpose of this class is to workaound a bug in glibc's pthread_cond_broadcast/signal(), which is also used by std::condition_variable.

The bug is already fixed here: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=8f630cca5c36941db1cb48726016bbed80ec1041 However, it will not be available until glibc 2.20, which will be employed in major linux distros much much later. So, we work around the issue ourselves for a while.

Seems like the issue is not only about broadcast. I'm observing issues if we might call notify_one while there is no waiter (which should be totally valid, but then something gets occasionally broken.) So, whether you have at most one waiter not, we should use this class always. Do not use std::condition_variable at all.

As this depends on C++11, the name of this file ends with impl. Thus, only private implementation classes directly use this class. If you are okay with C++11, you can use it from client programs, too.

This class is totally header-only.

Definition at line 56 of file condition_variable_impl.hpp.

#include <condition_variable_impl.hpp>

Public Member Functions

 ConditionVariable ()
 
 ~ConditionVariable ()
 
 ConditionVariable (const ConditionVariable &other)=delete
 
ConditionVariableoperator= (const ConditionVariable &other)=delete
 
 ConditionVariable (ConditionVariable &&other)=delete
 
ConditionVariableoperator= (ConditionVariable &&other)=delete
 
template<typename PREDICATE >
void wait (PREDICATE predicate)
 Block until the event happens. More...
 
void wait ()
 Block until the event PROBABLY (because this version is w/o pred) happens. More...
 
template<class REP , class PERIOD , typename PREDICATE >
bool wait_for (const std::chrono::duration< REP, PERIOD > &timeout, PREDICATE predicate)
 Block until the event happens or the given period elapses. More...
 
template<class REP , class PERIOD >
bool wait_for (const std::chrono::duration< REP, PERIOD > &timeout)
 Block until the event happens or the given period elapses. More...
 
template<class CLOCK , class DURATION , typename PREDICATE >
bool wait_until (const std::chrono::time_point< CLOCK, DURATION > &until, PREDICATE predicate)
 Block until the event happens or the given time point arrives. More...
 
template<class CLOCK , class DURATION >
bool wait_until (const std::chrono::time_point< CLOCK, DURATION > &until)
 Block until the event happens or the given time point arrives. More...
 
template<typename SIGNAL_ACTION >
void notify_all (SIGNAL_ACTION signal_action)
 Notify all waiters that the event has happened. More...
 
void notify_all ()
 Notify all waiters that the event has happened. More...
 
template<typename SIGNAL_ACTION >
void notify_one (SIGNAL_ACTION signal_action)
 Notify one waiter that the event has happened. More...
 
void notify_one ()
 Notify one waiter that the event has happened. More...
 

Constructor & Destructor Documentation

foedus::thread::ConditionVariable::ConditionVariable ( )
inline

Definition at line 58 of file condition_variable_impl.hpp.

58 : waiters_(0), notifiers_(0) {}
foedus::thread::ConditionVariable::~ConditionVariable ( )
inline

Definition at line 59 of file condition_variable_impl.hpp.

References ASSERT_ND, and foedus::assorted::spinlock_yield().

59  {
60  ASSERT_ND(waiters_ == 0);
61  // we must wait until all notifiers exit notify_all.
62  // this assumes no new notifiers are newly coming in this situation.
63  while (notifiers_ > 0) {
65  }
66  }
void spinlock_yield()
Invoke _mm_pause(), x86 PAUSE instruction, or something equivalent in the env.
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
Definition: assert_nd.hpp:72

Here is the call graph for this function:

foedus::thread::ConditionVariable::ConditionVariable ( const ConditionVariable other)
delete
foedus::thread::ConditionVariable::ConditionVariable ( ConditionVariable &&  other)
delete

Member Function Documentation

template<typename SIGNAL_ACTION >
void foedus::thread::ConditionVariable::notify_all ( SIGNAL_ACTION  signal_action)
inline

Notify all waiters that the event has happened.

Parameters
[in]signal_actionFunctor to update actual values that changes the condition variable to signaling state. This will be executed in critical section to avoid lost signal and spurious wakeup.

Equivalent to std::condition_variable::notify_all(). To workaround the pthread_cond_broadcast bug, this method notifies one by one. We might add a switch of the behavior by checking glibc version.

Definition at line 153 of file condition_variable_impl.hpp.

References foedus::assorted::spinlock_yield().

Referenced by foedus::thread::Rendezvous::signal().

153  {
154  NotifierScope scope(this);
155  {
156  std::lock_guard<std::mutex> guard(mutex_);
157  signal_action(); // conduct the action to update actual values *in* critical section
158  }
159  while (waiters_ > 0) {
160  condition_.notify_one();
162  }
163  }
void spinlock_yield()
Invoke _mm_pause(), x86 PAUSE instruction, or something equivalent in the env.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::thread::ConditionVariable::notify_all ( )
inline

Notify all waiters that the event has happened.

Equivalent to std::condition_variable::notify_all(). To workaround the pthread_cond_broadcast bug, this method notifies one by one. We might add a switch of the behavior by checking glibc version.

Definition at line 171 of file condition_variable_impl.hpp.

171  {
172  notify_all([]{});
173  }
void notify_all()
Notify all waiters that the event has happened.
template<typename SIGNAL_ACTION >
void foedus::thread::ConditionVariable::notify_one ( SIGNAL_ACTION  signal_action)
inline

Notify one waiter that the event has happened.

Parameters
[in]signal_actionFunctor to update actual values that changes the condition variable to signaling state. This will be executed in critical section to avoid lost signal and spurious wakeup.

Equivalent to std::condition_variable::notify_one(). To workaround the pthread_cond_signal bug, this method atomically checks if there is any waiter, avoiding to call notify_one() if there is none. We might add a switch of the behavior by checking glibc version.

Definition at line 187 of file condition_variable_impl.hpp.

Referenced by foedus::thread::StoppableThread::request_stop(), and foedus::thread::StoppableThread::wakeup().

187  {
188  NotifierScope scope(this);
189  {
190  std::lock_guard<std::mutex> guard(mutex_);
191  signal_action();
192  }
193  if (waiters_ > 0) {
194  condition_.notify_one();
195  }
196  }

Here is the caller graph for this function:

void foedus::thread::ConditionVariable::notify_one ( )
inline

Notify one waiter that the event has happened.

Equivalent to std::condition_variable::notify_one(). To workaround the pthread_cond_signal bug, this method atomically checks if there is any waiter, avoiding to call notify_one() if there is none. We might add a switch of the behavior by checking glibc version.

Definition at line 206 of file condition_variable_impl.hpp.

206  {
207  notify_one([]{});
208  }
void notify_one()
Notify one waiter that the event has happened.
ConditionVariable& foedus::thread::ConditionVariable::operator= ( const ConditionVariable other)
delete
ConditionVariable& foedus::thread::ConditionVariable::operator= ( ConditionVariable &&  other)
delete
template<typename PREDICATE >
void foedus::thread::ConditionVariable::wait ( PREDICATE  predicate)
inline

Block until the event happens.

Equivalent to std::condition_variable::wait().

Definition at line 80 of file condition_variable_impl.hpp.

Referenced by foedus::thread::Rendezvous::wait().

80  {
81  WaiterScope scope(this);
82  condition_.wait(scope.lock_, predicate);
83  }

Here is the caller graph for this function:

void foedus::thread::ConditionVariable::wait ( )
inline

Block until the event PROBABLY (because this version is w/o pred) happens.

Equivalent to std::condition_variable::wait().

Definition at line 89 of file condition_variable_impl.hpp.

89  {
90  WaiterScope scope(this);
91  condition_.wait(scope.lock_);
92  }
template<class REP , class PERIOD , typename PREDICATE >
bool foedus::thread::ConditionVariable::wait_for ( const std::chrono::duration< REP, PERIOD > &  timeout,
PREDICATE  predicate 
)
inline

Block until the event happens or the given period elapses.

Returns
whether the event happened by now.

Equivalent to std::condition_variable::wait_for().

Definition at line 101 of file condition_variable_impl.hpp.

Referenced by foedus::thread::StoppableThread::sleep(), and foedus::thread::Rendezvous::wait_for().

101  {
102  WaiterScope scope(this);
103  return condition_.wait_for(scope.lock_, timeout, predicate);
104  }

Here is the caller graph for this function:

template<class REP , class PERIOD >
bool foedus::thread::ConditionVariable::wait_for ( const std::chrono::duration< REP, PERIOD > &  timeout)
inline

Block until the event happens or the given period elapses.

Returns
whether the event PROBABLY (because this version is w/o pred) happened by now.

Equivalent to std::condition_variable::wait_for().

Definition at line 113 of file condition_variable_impl.hpp.

113  {
114  WaiterScope scope(this);
115  return condition_.wait_for(scope.lock_, timeout) == std::cv_status::no_timeout;
116  }
template<class CLOCK , class DURATION , typename PREDICATE >
bool foedus::thread::ConditionVariable::wait_until ( const std::chrono::time_point< CLOCK, DURATION > &  until,
PREDICATE  predicate 
)
inline

Block until the event happens or the given time point arrives.

Returns
whether the event happened by now.

Equivalent to std::condition_variable::wait_until().

Definition at line 125 of file condition_variable_impl.hpp.

Referenced by foedus::thread::Rendezvous::wait_until().

125  {
126  WaiterScope scope(this);
127  return condition_.wait_until(scope.lock_, until, predicate);
128  }

Here is the caller graph for this function:

template<class CLOCK , class DURATION >
bool foedus::thread::ConditionVariable::wait_until ( const std::chrono::time_point< CLOCK, DURATION > &  until)
inline

Block until the event happens or the given time point arrives.

Returns
whether the event PROBABLY (because this version is w/o pred) happened by now.

Equivalent to std::condition_variable::wait_until().

Definition at line 137 of file condition_variable_impl.hpp.

137  {
138  WaiterScope scope(this);
139  return condition_.wait_until(scope.lock_, until) == std::cv_status::no_timeout;
140  }

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