libfoedus-core
FOEDUS Core Library
condition_variable_impl.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
18 #ifndef FOEDUS_THREAD_CONDITION_VARIABLE_IMPL_HPP_
19 #define FOEDUS_THREAD_CONDITION_VARIABLE_IMPL_HPP_
20 #include <stdint.h>
21 
22 #include <atomic>
23 #include <chrono>
24 #include <condition_variable>
25 #include <mutex>
26 
27 #include "foedus/assert_nd.hpp"
29 
30 namespace foedus {
31 namespace thread {
56 class ConditionVariable final {
57  public:
58  ConditionVariable() : waiters_(0), notifiers_(0) {}
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  }
67 
68  // not copyable, assignable.
69  ConditionVariable(const ConditionVariable &other) = delete;
70  ConditionVariable& operator=(const ConditionVariable &other) = delete;
71  ConditionVariable(ConditionVariable &&other) = delete;
73 
79  template<typename PREDICATE>
80  void wait(PREDICATE predicate) {
81  WaiterScope scope(this);
82  condition_.wait(scope.lock_, predicate);
83  }
89  void wait() {
90  WaiterScope scope(this);
91  condition_.wait(scope.lock_);
92  }
93 
100  template<class REP, class PERIOD, typename PREDICATE>
101  bool wait_for(const std::chrono::duration<REP, PERIOD>& timeout, PREDICATE predicate) {
102  WaiterScope scope(this);
103  return condition_.wait_for(scope.lock_, timeout, predicate);
104  }
105 
112  template<class REP, class PERIOD>
113  bool wait_for(const std::chrono::duration<REP, PERIOD>& timeout) {
114  WaiterScope scope(this);
115  return condition_.wait_for(scope.lock_, timeout) == std::cv_status::no_timeout;
116  }
117 
124  template< class CLOCK, class DURATION, typename PREDICATE>
125  bool wait_until(const std::chrono::time_point<CLOCK, DURATION>& until, PREDICATE predicate) {
126  WaiterScope scope(this);
127  return condition_.wait_until(scope.lock_, until, predicate);
128  }
129 
136  template< class CLOCK, class DURATION>
137  bool wait_until(const std::chrono::time_point<CLOCK, DURATION>& until) {
138  WaiterScope scope(this);
139  return condition_.wait_until(scope.lock_, until) == std::cv_status::no_timeout;
140  }
141 
152  template<typename SIGNAL_ACTION>
153  void notify_all(SIGNAL_ACTION signal_action) {
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  }
171  void notify_all() {
172  notify_all([]{});
173  }
174 
186  template<typename SIGNAL_ACTION>
187  void notify_one(SIGNAL_ACTION signal_action) {
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  }
197 
206  void notify_one() {
207  notify_one([]{});
208  }
209 
210  private:
212  std::condition_variable condition_;
218  std::mutex mutex_;
219 
221  std::atomic<uint32_t> waiters_;
223  std::atomic<uint32_t> notifiers_;
224 
226  struct WaiterScope {
227  explicit WaiterScope(ConditionVariable* enclosure)
228  : enclosure_(enclosure), lock_(enclosure_->mutex_) {
229  ASSERT_ND(lock_.owns_lock());
230  ++enclosure_->waiters_;
231  }
232  ~WaiterScope() {
233  ASSERT_ND(lock_.owns_lock());
234  ASSERT_ND(enclosure_->waiters_ > 0);
235  --enclosure_->waiters_;
236  }
237  ConditionVariable* const enclosure_;
238  std::unique_lock<std::mutex> lock_;
239  };
241  struct NotifierScope {
242  explicit NotifierScope(ConditionVariable* enclosure) : enclosure_(enclosure) {
243  ++enclosure_->notifiers_;
244  }
245  ~NotifierScope() {
246  ASSERT_ND(enclosure_->notifiers_ > 0);
247  --enclosure_->notifiers_;
248  }
249  ConditionVariable* const enclosure_;
250  };
251 };
252 
253 
254 } // namespace thread
255 } // namespace foedus
256 #endif // FOEDUS_THREAD_CONDITION_VARIABLE_IMPL_HPP_
ConditionVariable & operator=(const ConditionVariable &other)=delete
void notify_all(SIGNAL_ACTION signal_action)
Notify all waiters that the event has happened.
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
void notify_one()
Notify one waiter that the event has happened.
bool wait_for(const std::chrono::duration< REP, PERIOD > &timeout)
Block until the event happens or the given period elapses.
void notify_all()
Notify all waiters that the event has happened.
bool wait_for(const std::chrono::duration< REP, PERIOD > &timeout, PREDICATE predicate)
Block until the event happens or the given period elapses.
An analogue of pthread's condition variable and std::condition_variable to avoid glibc's bug in pthre...
void spinlock_yield()
Invoke _mm_pause(), x86 PAUSE instruction, or something equivalent in the env.
bool wait_until(const std::chrono::time_point< CLOCK, DURATION > &until)
Block until the event happens or the given time point arrives.
void wait()
Block until the event PROBABLY (because this version is w/o pred) happens.
bool wait_until(const std::chrono::time_point< CLOCK, DURATION > &until, PREDICATE predicate)
Block until the event happens or the given time point arrives.
void wait(PREDICATE predicate)
Block until the event happens.
void notify_one(SIGNAL_ACTION signal_action)
Notify one waiter that the event has happened.
#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