libstdc++
condition_variable
Go to the documentation of this file.
1 // <condition_variable> -*- C++ -*-
2 
3 // Copyright (C) 2008-2020 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 
40 #include <bits/std_mutex.h>
41 #include <bits/unique_lock.h>
42 #include <ext/concurrence.h>
43 #include <bits/alloc_traits.h>
44 #include <bits/allocator.h>
45 #include <bits/unique_ptr.h>
46 #include <bits/shared_ptr.h>
47 #include <bits/cxxabi_forced.h>
48 
49 #if __cplusplus > 201703L
50 #define __cpp_lib_jthread 201907L
51 #include <stop_token>
52 #endif
53 
54 #if defined(_GLIBCXX_HAS_GTHREADS)
55 
56 namespace std _GLIBCXX_VISIBILITY(default)
57 {
58 _GLIBCXX_BEGIN_NAMESPACE_VERSION
59 
60  /**
61  * @defgroup condition_variables Condition Variables
62  * @ingroup concurrency
63  *
64  * Classes for condition_variable support.
65  * @{
66  */
67 
68  /// cv_status
69  enum class cv_status { no_timeout, timeout };
70 
71  /// condition_variable
72  class condition_variable
73  {
74  using steady_clock = chrono::steady_clock;
75  using system_clock = chrono::system_clock;
76 #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
77  using __clock_t = steady_clock;
78 #else
79  using __clock_t = system_clock;
80 #endif
81  typedef __gthread_cond_t __native_type;
82 
83 #ifdef __GTHREAD_COND_INIT
84  __native_type _M_cond = __GTHREAD_COND_INIT;
85 #else
86  __native_type _M_cond;
87 #endif
88 
89  public:
90  typedef __native_type* native_handle_type;
91 
92  condition_variable() noexcept;
93  ~condition_variable() noexcept;
94 
95  condition_variable(const condition_variable&) = delete;
96  condition_variable& operator=(const condition_variable&) = delete;
97 
98  void
99  notify_one() noexcept;
100 
101  void
102  notify_all() noexcept;
103 
104  void
105  wait(unique_lock<mutex>& __lock) noexcept;
106 
107  template<typename _Predicate>
108  void
109  wait(unique_lock<mutex>& __lock, _Predicate __p)
110  {
111  while (!__p())
112  wait(__lock);
113  }
114 
115 #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
116  template<typename _Duration>
117  cv_status
118  wait_until(unique_lock<mutex>& __lock,
119  const chrono::time_point<steady_clock, _Duration>& __atime)
120  { return __wait_until_impl(__lock, __atime); }
121 #endif
122 
123  template<typename _Duration>
124  cv_status
125  wait_until(unique_lock<mutex>& __lock,
126  const chrono::time_point<system_clock, _Duration>& __atime)
127  { return __wait_until_impl(__lock, __atime); }
128 
129  template<typename _Clock, typename _Duration>
130  cv_status
131  wait_until(unique_lock<mutex>& __lock,
132  const chrono::time_point<_Clock, _Duration>& __atime)
133  {
134  const typename _Clock::time_point __c_entry = _Clock::now();
135  const __clock_t::time_point __s_entry = __clock_t::now();
136  const auto __delta = __atime - __c_entry;
137  const auto __s_atime = __s_entry + __delta;
138 
139  if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout)
140  return cv_status::no_timeout;
141  // We got a timeout when measured against __clock_t but
142  // we need to check against the caller-supplied clock
143  // to tell whether we should return a timeout.
144  if (_Clock::now() < __atime)
145  return cv_status::no_timeout;
146  return cv_status::timeout;
147  }
148 
149  template<typename _Clock, typename _Duration, typename _Predicate>
150  bool
151  wait_until(unique_lock<mutex>& __lock,
152  const chrono::time_point<_Clock, _Duration>& __atime,
153  _Predicate __p)
154  {
155  while (!__p())
156  if (wait_until(__lock, __atime) == cv_status::timeout)
157  return __p();
158  return true;
159  }
160 
161  template<typename _Rep, typename _Period>
162  cv_status
163  wait_for(unique_lock<mutex>& __lock,
164  const chrono::duration<_Rep, _Period>& __rtime)
165  {
166  using __dur = typename steady_clock::duration;
167  auto __reltime = chrono::duration_cast<__dur>(__rtime);
168  if (__reltime < __rtime)
169  ++__reltime;
170  return wait_until(__lock, steady_clock::now() + __reltime);
171  }
172 
173  template<typename _Rep, typename _Period, typename _Predicate>
174  bool
175  wait_for(unique_lock<mutex>& __lock,
176  const chrono::duration<_Rep, _Period>& __rtime,
177  _Predicate __p)
178  {
179  using __dur = typename steady_clock::duration;
180  auto __reltime = chrono::duration_cast<__dur>(__rtime);
181  if (__reltime < __rtime)
182  ++__reltime;
183  return wait_until(__lock, steady_clock::now() + __reltime,
184  std::move(__p));
185  }
186 
187  native_handle_type
188  native_handle()
189  { return &_M_cond; }
190 
191  private:
192 #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
193  template<typename _Dur>
194  cv_status
195  __wait_until_impl(unique_lock<mutex>& __lock,
196  const chrono::time_point<steady_clock, _Dur>& __atime)
197  {
198  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
199  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
200 
201  __gthread_time_t __ts =
202  {
203  static_cast<std::time_t>(__s.time_since_epoch().count()),
204  static_cast<long>(__ns.count())
205  };
206 
207  pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(),
208  CLOCK_MONOTONIC,
209  &__ts);
210 
211  return (steady_clock::now() < __atime
212  ? cv_status::no_timeout : cv_status::timeout);
213  }
214 #endif
215 
216  template<typename _Dur>
217  cv_status
218  __wait_until_impl(unique_lock<mutex>& __lock,
219  const chrono::time_point<system_clock, _Dur>& __atime)
220  {
221  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
222  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
223 
224  __gthread_time_t __ts =
225  {
226  static_cast<std::time_t>(__s.time_since_epoch().count()),
227  static_cast<long>(__ns.count())
228  };
229 
230  __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
231  &__ts);
232 
233  return (system_clock::now() < __atime
234  ? cv_status::no_timeout : cv_status::timeout);
235  }
236  };
237 
238  void
239  notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
240 
241  struct __at_thread_exit_elt
242  {
243  __at_thread_exit_elt* _M_next;
244  void (*_M_cb)(void*);
245  };
246 
247  inline namespace _V2 {
248 
249  /// condition_variable_any
250  // Like above, but mutex is not required to have try_lock.
251  class condition_variable_any
252  {
253 #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
254  using __clock_t = chrono::steady_clock;
255 #else
256  using __clock_t = chrono::system_clock;
257 #endif
258  condition_variable _M_cond;
259  shared_ptr<mutex> _M_mutex;
260 
261  // scoped unlock - unlocks in ctor, re-locks in dtor
262  template<typename _Lock>
263  struct _Unlock
264  {
265  explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
266 
267  ~_Unlock() noexcept(false)
268  {
269  if (uncaught_exception())
270  {
271  __try
272  { _M_lock.lock(); }
273  __catch(const __cxxabiv1::__forced_unwind&)
274  { __throw_exception_again; }
275  __catch(...)
276  { }
277  }
278  else
279  _M_lock.lock();
280  }
281 
282  _Unlock(const _Unlock&) = delete;
283  _Unlock& operator=(const _Unlock&) = delete;
284 
285  _Lock& _M_lock;
286  };
287 
288  public:
289  condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
290  ~condition_variable_any() = default;
291 
292  condition_variable_any(const condition_variable_any&) = delete;
293  condition_variable_any& operator=(const condition_variable_any&) = delete;
294 
295  void
296  notify_one() noexcept
297  {
298  lock_guard<mutex> __lock(*_M_mutex);
299  _M_cond.notify_one();
300  }
301 
302  void
303  notify_all() noexcept
304  {
305  lock_guard<mutex> __lock(*_M_mutex);
306  _M_cond.notify_all();
307  }
308 
309  template<typename _Lock>
310  void
311  wait(_Lock& __lock)
312  {
313  shared_ptr<mutex> __mutex = _M_mutex;
314  unique_lock<mutex> __my_lock(*__mutex);
315  _Unlock<_Lock> __unlock(__lock);
316  // *__mutex must be unlocked before re-locking __lock so move
317  // ownership of *__mutex lock to an object with shorter lifetime.
318  unique_lock<mutex> __my_lock2(std::move(__my_lock));
319  _M_cond.wait(__my_lock2);
320  }
321 
322 
323  template<typename _Lock, typename _Predicate>
324  void
325  wait(_Lock& __lock, _Predicate __p)
326  {
327  while (!__p())
328  wait(__lock);
329  }
330 
331  template<typename _Lock, typename _Clock, typename _Duration>
332  cv_status
333  wait_until(_Lock& __lock,
334  const chrono::time_point<_Clock, _Duration>& __atime)
335  {
336  shared_ptr<mutex> __mutex = _M_mutex;
337  unique_lock<mutex> __my_lock(*__mutex);
338  _Unlock<_Lock> __unlock(__lock);
339  // *__mutex must be unlocked before re-locking __lock so move
340  // ownership of *__mutex lock to an object with shorter lifetime.
341  unique_lock<mutex> __my_lock2(std::move(__my_lock));
342  return _M_cond.wait_until(__my_lock2, __atime);
343  }
344 
345  template<typename _Lock, typename _Clock,
346  typename _Duration, typename _Predicate>
347  bool
348  wait_until(_Lock& __lock,
349  const chrono::time_point<_Clock, _Duration>& __atime,
350  _Predicate __p)
351  {
352  while (!__p())
353  if (wait_until(__lock, __atime) == cv_status::timeout)
354  return __p();
355  return true;
356  }
357 
358  template<typename _Lock, typename _Rep, typename _Period>
359  cv_status
360  wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
361  { return wait_until(__lock, __clock_t::now() + __rtime); }
362 
363  template<typename _Lock, typename _Rep,
364  typename _Period, typename _Predicate>
365  bool
366  wait_for(_Lock& __lock,
367  const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
368  { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
369 
370 #ifdef __cpp_lib_jthread
371  template <class _Lock, class _Predicate>
372  bool wait(_Lock& __lock,
373  stop_token __stoken,
374  _Predicate __p)
375  {
376  if (__stoken.stop_requested())
377  {
378  return __p();
379  }
380 
381  std::stop_callback __cb(__stoken, [this] { notify_all(); });
382  shared_ptr<mutex> __mutex = _M_mutex;
383  while (!__p())
384  {
385  unique_lock<mutex> __my_lock(*__mutex);
386  if (__stoken.stop_requested())
387  {
388  return false;
389  }
390  // *__mutex must be unlocked before re-locking __lock so move
391  // ownership of *__mutex lock to an object with shorter lifetime.
392  _Unlock<_Lock> __unlock(__lock);
393  unique_lock<mutex> __my_lock2(std::move(__my_lock));
394  _M_cond.wait(__my_lock2);
395  }
396  return true;
397  }
398 
399  template <class _Lock, class _Clock, class _Duration, class _Predicate>
400  bool wait_until(_Lock& __lock,
401  stop_token __stoken,
402  const chrono::time_point<_Clock, _Duration>& __abs_time,
403  _Predicate __p)
404  {
405  if (__stoken.stop_requested())
406  {
407  return __p();
408  }
409 
410  std::stop_callback __cb(__stoken, [this] { notify_all(); });
411  shared_ptr<mutex> __mutex = _M_mutex;
412  while (!__p())
413  {
414  bool __stop;
415  {
416  unique_lock<mutex> __my_lock(*__mutex);
417  if (__stoken.stop_requested())
418  {
419  return false;
420  }
421  _Unlock<_Lock> __u(__lock);
422  unique_lock<mutex> __my_lock2(std::move(__my_lock));
423  const auto __status = _M_cond.wait_until(__my_lock2, __abs_time);
424  __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested();
425  }
426  if (__stop)
427  {
428  return __p();
429  }
430  }
431  return true;
432  }
433 
434  template <class _Lock, class _Rep, class _Period, class _Predicate>
435  bool wait_for(_Lock& __lock,
436  stop_token __stoken,
437  const chrono::duration<_Rep, _Period>& __rel_time,
438  _Predicate __p)
439  {
440  auto __abst = std::chrono::steady_clock::now() + __rel_time;
441  return wait_until(__lock,
442  std::move(__stoken),
443  __abst,
444  std::move(__p));
445  }
446 #endif
447  };
448 
449  } // end inline namespace
450 
451  // @} group condition_variables
452 _GLIBCXX_END_NAMESPACE_VERSION
453 } // namespace
454 
455 #endif // _GLIBCXX_HAS_GTHREADS
456 #endif // C++11
457 #endif // _GLIBCXX_CONDITION_VARIABLE