libstdc++
condition_variable
Go to the documentation of this file.
1 // <condition_variable> -*- C++ -*-
2 
3 // Copyright (C) 2008-2013 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file include/condition_variable
26  * This is a Standard C++ Library header.
27  */
28 
29 #ifndef _GLIBCXX_CONDITION_VARIABLE
30 #define _GLIBCXX_CONDITION_VARIABLE 1
31 
32 #pragma GCC system_header
33 
34 #if __cplusplus < 201103L
35 # include <bits/c++0x_warning.h>
36 #else
37 
38 #include <chrono>
39 #include <mutex> // unique_lock
40 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
41 # include <memory>
42 #endif
43 
44 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
45 
46 namespace std _GLIBCXX_VISIBILITY(default)
47 {
48 _GLIBCXX_BEGIN_NAMESPACE_VERSION
49 
50  /**
51  * @defgroup condition_variables Condition Variables
52  * @ingroup concurrency
53  *
54  * Classes for condition_variable support.
55  * @{
56  */
57 
58  /// cv_status
59  enum class cv_status { no_timeout, timeout };
60 
61  /// condition_variable
63  {
64  typedef chrono::system_clock __clock_t;
65  typedef __gthread_cond_t __native_type;
66 
67 #ifdef __GTHREAD_COND_INIT
68  __native_type _M_cond = __GTHREAD_COND_INIT;
69 #else
70  __native_type _M_cond;
71 #endif
72 
73  public:
74  typedef __native_type* native_handle_type;
75 
76  condition_variable() noexcept;
77  ~condition_variable() noexcept;
78 
79  condition_variable(const condition_variable&) = delete;
80  condition_variable& operator=(const condition_variable&) = delete;
81 
82  void
83  notify_one() noexcept;
84 
85  void
86  notify_all() noexcept;
87 
88  void
89  wait(unique_lock<mutex>& __lock);
90 
91  template<typename _Predicate>
92  void
93  wait(unique_lock<mutex>& __lock, _Predicate __p)
94  {
95  while (!__p())
96  wait(__lock);
97  }
98 
99  template<typename _Duration>
100  cv_status
101  wait_until(unique_lock<mutex>& __lock,
103  { return __wait_until_impl(__lock, __atime); }
104 
105  template<typename _Clock, typename _Duration>
106  cv_status
107  wait_until(unique_lock<mutex>& __lock,
109  {
110  // DR 887 - Sync unknown clock to known clock.
111  const typename _Clock::time_point __c_entry = _Clock::now();
112  const __clock_t::time_point __s_entry = __clock_t::now();
113  const auto __delta = __atime - __c_entry;
114  const auto __s_atime = __s_entry + __delta;
115 
116  return __wait_until_impl(__lock, __s_atime);
117  }
118 
119  template<typename _Clock, typename _Duration, typename _Predicate>
120  bool
121  wait_until(unique_lock<mutex>& __lock,
123  _Predicate __p)
124  {
125  while (!__p())
126  if (wait_until(__lock, __atime) == cv_status::timeout)
127  return __p();
128  return true;
129  }
130 
131  template<typename _Rep, typename _Period>
132  cv_status
133  wait_for(unique_lock<mutex>& __lock,
134  const chrono::duration<_Rep, _Period>& __rtime)
135  { return wait_until(__lock, __clock_t::now() + __rtime); }
136 
137  template<typename _Rep, typename _Period, typename _Predicate>
138  bool
139  wait_for(unique_lock<mutex>& __lock,
140  const chrono::duration<_Rep, _Period>& __rtime,
141  _Predicate __p)
142  { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
143 
144  native_handle_type
145  native_handle()
146  { return &_M_cond; }
147 
148  private:
149  template<typename _Dur>
150  cv_status
151  __wait_until_impl(unique_lock<mutex>& __lock,
153  {
154  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
155  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
156 
157  __gthread_time_t __ts =
158  {
159  static_cast<std::time_t>(__s.time_since_epoch().count()),
160  static_cast<long>(__ns.count())
161  };
162 
163  __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
164  &__ts);
165 
166  return (__clock_t::now() < __atime
167  ? cv_status::no_timeout : cv_status::timeout);
168  }
169  };
170 
171 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
172  inline namespace _V2 {
173 #endif
174 
175  /// condition_variable_any
176  // Like above, but mutex is not required to have try_lock.
178  {
179  typedef chrono::system_clock __clock_t;
180  condition_variable _M_cond;
181 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
182  shared_ptr<mutex> _M_mutex;
183 #else
184  mutex _M_mutex;
185 #endif
186 
187  // scoped unlock - unlocks in ctor, re-locks in dtor
188  template<typename _Lock>
189  struct _Unlock
190  {
191  explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
192 
193  ~_Unlock() noexcept(false)
194  {
195  if (uncaught_exception())
196  __try { _M_lock.lock(); } __catch(...) { }
197  else
198  _M_lock.lock();
199  }
200 
201  _Unlock(const _Unlock&) = delete;
202  _Unlock& operator=(const _Unlock&) = delete;
203 
204  _Lock& _M_lock;
205  };
206 
207  public:
208 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
209  condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
210  ~condition_variable_any() = default;
211 #else
212  condition_variable_any() noexcept;
213  ~condition_variable_any() noexcept;
214 #endif
215 
217  condition_variable_any& operator=(const condition_variable_any&) = delete;
218 
219  void
220  notify_one() noexcept
221  {
222 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
223  lock_guard<mutex> __lock(*_M_mutex);
224 #else
225  lock_guard<mutex> __lock(_M_mutex);
226 #endif
227  _M_cond.notify_one();
228  }
229 
230  void
231  notify_all() noexcept
232  {
233 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
234  lock_guard<mutex> __lock(*_M_mutex);
235 #else
236  lock_guard<mutex> __lock(_M_mutex);
237 #endif
238  _M_cond.notify_all();
239  }
240 
241  template<typename _Lock>
242  void
243  wait(_Lock& __lock)
244  {
245 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
246  shared_ptr<mutex> __mutex = _M_mutex;
247  unique_lock<mutex> __my_lock(*__mutex);
248 #else
249  unique_lock<mutex> __my_lock(_M_mutex);
250 #endif
251  _Unlock<_Lock> __unlock(__lock);
252  // _M_mutex must be unlocked before re-locking __lock so move
253  // ownership of _M_mutex lock to an object with shorter lifetime.
254  unique_lock<mutex> __my_lock2(std::move(__my_lock));
255  _M_cond.wait(__my_lock2);
256  }
257 
258 
259  template<typename _Lock, typename _Predicate>
260  void
261  wait(_Lock& __lock, _Predicate __p)
262  {
263  while (!__p())
264  wait(__lock);
265  }
266 
267  template<typename _Lock, typename _Clock, typename _Duration>
268  cv_status
269  wait_until(_Lock& __lock,
271  {
272 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
273  shared_ptr<mutex> __mutex = _M_mutex;
274  unique_lock<mutex> __my_lock(*__mutex);
275 #else
276  unique_lock<mutex> __my_lock(_M_mutex);
277 #endif
278  _Unlock<_Lock> __unlock(__lock);
279  // _M_mutex must be unlocked before re-locking __lock so move
280  // ownership of _M_mutex lock to an object with shorter lifetime.
281  unique_lock<mutex> __my_lock2(std::move(__my_lock));
282  return _M_cond.wait_until(__my_lock2, __atime);
283  }
284 
285  template<typename _Lock, typename _Clock,
286  typename _Duration, typename _Predicate>
287  bool
288  wait_until(_Lock& __lock,
290  _Predicate __p)
291  {
292  while (!__p())
293  if (wait_until(__lock, __atime) == cv_status::timeout)
294  return __p();
295  return true;
296  }
297 
298  template<typename _Lock, typename _Rep, typename _Period>
299  cv_status
300  wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
301  { return wait_until(__lock, __clock_t::now() + __rtime); }
302 
303  template<typename _Lock, typename _Rep,
304  typename _Period, typename _Predicate>
305  bool
306  wait_for(_Lock& __lock,
307  const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
308  { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
309  };
310 
311 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
312  } // end inline namespace
313 #endif
314 
315  // @} group condition_variables
316 _GLIBCXX_END_NAMESPACE_VERSION
317 } // namespace
318 
319 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
320 
321 #endif // C++11
322 
323 #endif // _GLIBCXX_CONDITION_VARIABLE
mutex
Definition: mutex:117
constexpr enable_if< __is_duration< _ToDur >::value, time_point< _Clock, _ToDur > >::type time_point_cast(const time_point< _Clock, _Dur > &__t)
time_point_cast
Definition: chrono:602
condition_variable_any
bool uncaught_exception() noexcept __attribute__((__pure__))
A smart pointer with reference-counted copy semantics.
Definition: shared_ptr.h:93
Scoped lock idiom.
Definition: mutex:408
duration
Definition: chrono:63
condition_variable
time_point
Definition: chrono:66
unique_lock
Definition: mutex:431
constexpr enable_if< __is_duration< _ToDur >::value, _ToDur >::type duration_cast(const duration< _Rep, _Period > &__d)
duration_cast
Definition: chrono:193
cv_status
cv_status