1// <condition_variable> -*- C++ -*-
3// Copyright (C) 2008-2021 Free Software Foundation, Inc.
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)
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.
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.
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/>.
25/** @file include/condition_variable
26 * This is a Standard C++ Library header.
29#ifndef _GLIBCXX_CONDITION_VARIABLE
30#define _GLIBCXX_CONDITION_VARIABLE 1
32#pragma GCC system_header
34#if __cplusplus < 201103L
35# include <bits/c++0x_warning.h>
40#include <bits/std_mutex.h>
41#include <bits/unique_lock.h>
42#include <bits/alloc_traits.h>
43#include <bits/shared_ptr.h>
44#include <bits/cxxabi_forced.h>
46#if __cplusplus > 201703L
50#if defined(_GLIBCXX_HAS_GTHREADS)
52namespace std _GLIBCXX_VISIBILITY(default)
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
57 * @defgroup condition_variables Condition Variables
58 * @ingroup concurrency
60 * Classes for condition_variable support.
65 enum class cv_status { no_timeout, timeout };
67 /// condition_variable
68 class condition_variable
70 using steady_clock = chrono::steady_clock;
71 using system_clock = chrono::system_clock;
72#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
73 using __clock_t = steady_clock;
75 using __clock_t = system_clock;
81 typedef __gthread_cond_t* native_handle_type;
83 condition_variable() noexcept;
84 ~condition_variable() noexcept;
86 condition_variable(const condition_variable&) = delete;
87 condition_variable& operator=(const condition_variable&) = delete;
90 notify_one() noexcept;
93 notify_all() noexcept;
96 wait(unique_lock<mutex>& __lock) noexcept;
98 template<typename _Predicate>
100 wait(unique_lock<mutex>& __lock, _Predicate __p)
106#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
107 template<typename _Duration>
109 wait_until(unique_lock<mutex>& __lock,
110 const chrono::time_point<steady_clock, _Duration>& __atime)
111 { return __wait_until_impl(__lock, __atime); }
114 template<typename _Duration>
116 wait_until(unique_lock<mutex>& __lock,
117 const chrono::time_point<system_clock, _Duration>& __atime)
118 { return __wait_until_impl(__lock, __atime); }
120 template<typename _Clock, typename _Duration>
122 wait_until(unique_lock<mutex>& __lock,
123 const chrono::time_point<_Clock, _Duration>& __atime)
125#if __cplusplus > 201703L
126 static_assert(chrono::is_clock_v<_Clock>);
128 using __s_dur = typename __clock_t::duration;
129 const typename _Clock::time_point __c_entry = _Clock::now();
130 const __clock_t::time_point __s_entry = __clock_t::now();
131 const auto __delta = __atime - __c_entry;
132 const auto __s_atime = __s_entry +
133 chrono::__detail::ceil<__s_dur>(__delta);
135 if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout)
136 return cv_status::no_timeout;
137 // We got a timeout when measured against __clock_t but
138 // we need to check against the caller-supplied clock
139 // to tell whether we should return a timeout.
140 if (_Clock::now() < __atime)
141 return cv_status::no_timeout;
142 return cv_status::timeout;
145 template<typename _Clock, typename _Duration, typename _Predicate>
147 wait_until(unique_lock<mutex>& __lock,
148 const chrono::time_point<_Clock, _Duration>& __atime,
152 if (wait_until(__lock, __atime) == cv_status::timeout)
157 template<typename _Rep, typename _Period>
159 wait_for(unique_lock<mutex>& __lock,
160 const chrono::duration<_Rep, _Period>& __rtime)
162 using __dur = typename steady_clock::duration;
163 return wait_until(__lock,
164 steady_clock::now() +
165 chrono::__detail::ceil<__dur>(__rtime));
168 template<typename _Rep, typename _Period, typename _Predicate>
170 wait_for(unique_lock<mutex>& __lock,
171 const chrono::duration<_Rep, _Period>& __rtime,
174 using __dur = typename steady_clock::duration;
175 return wait_until(__lock,
176 steady_clock::now() +
177 chrono::__detail::ceil<__dur>(__rtime),
183 { return _M_cond.native_handle(); }
186#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
187 template<typename _Dur>
189 __wait_until_impl(unique_lock<mutex>& __lock,
190 const chrono::time_point<steady_clock, _Dur>& __atime)
192 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
193 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
195 __gthread_time_t __ts =
197 static_cast<std::time_t>(__s.time_since_epoch().count()),
198 static_cast<long>(__ns.count())
201 _M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
203 return (steady_clock::now() < __atime
204 ? cv_status::no_timeout : cv_status::timeout);
208 template<typename _Dur>
210 __wait_until_impl(unique_lock<mutex>& __lock,
211 const chrono::time_point<system_clock, _Dur>& __atime)
213 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
214 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
216 __gthread_time_t __ts =
218 static_cast<std::time_t>(__s.time_since_epoch().count()),
219 static_cast<long>(__ns.count())
222 _M_cond.wait_until(*__lock.mutex(), __ts);
224 return (system_clock::now() < __atime
225 ? cv_status::no_timeout : cv_status::timeout);
230 notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
232 struct __at_thread_exit_elt
234 __at_thread_exit_elt* _M_next;
235 void (*_M_cb)(void*);
238 inline namespace _V2 {
240 /// condition_variable_any
241 // Like above, but mutex is not required to have try_lock.
242 class condition_variable_any
244#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
245 using __clock_t = chrono::steady_clock;
247 using __clock_t = chrono::system_clock;
249 condition_variable _M_cond;
250 shared_ptr<mutex> _M_mutex;
252 // scoped unlock - unlocks in ctor, re-locks in dtor
253 template<typename _Lock>
256 explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
258#pragma GCC diagnostic push
259#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
260 ~_Unlock() noexcept(false)
262 if (uncaught_exception())
266 __catch(const __cxxabiv1::__forced_unwind&)
267 { __throw_exception_again; }
274#pragma GCC diagnostic pop
276 _Unlock(const _Unlock&) = delete;
277 _Unlock& operator=(const _Unlock&) = delete;
283 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
284 ~condition_variable_any() = default;
286 condition_variable_any(const condition_variable_any&) = delete;
287 condition_variable_any& operator=(const condition_variable_any&) = delete;
290 notify_one() noexcept
292 lock_guard<mutex> __lock(*_M_mutex);
293 _M_cond.notify_one();
297 notify_all() noexcept
299 lock_guard<mutex> __lock(*_M_mutex);
300 _M_cond.notify_all();
303 template<typename _Lock>
307 shared_ptr<mutex> __mutex = _M_mutex;
308 unique_lock<mutex> __my_lock(*__mutex);
309 _Unlock<_Lock> __unlock(__lock);
310 // *__mutex must be unlocked before re-locking __lock so move
311 // ownership of *__mutex lock to an object with shorter lifetime.
312 unique_lock<mutex> __my_lock2(std::move(__my_lock));
313 _M_cond.wait(__my_lock2);
317 template<typename _Lock, typename _Predicate>
319 wait(_Lock& __lock, _Predicate __p)
325 template<typename _Lock, typename _Clock, typename _Duration>
327 wait_until(_Lock& __lock,
328 const chrono::time_point<_Clock, _Duration>& __atime)
330 shared_ptr<mutex> __mutex = _M_mutex;
331 unique_lock<mutex> __my_lock(*__mutex);
332 _Unlock<_Lock> __unlock(__lock);
333 // *__mutex must be unlocked before re-locking __lock so move
334 // ownership of *__mutex lock to an object with shorter lifetime.
335 unique_lock<mutex> __my_lock2(std::move(__my_lock));
336 return _M_cond.wait_until(__my_lock2, __atime);
339 template<typename _Lock, typename _Clock,
340 typename _Duration, typename _Predicate>
342 wait_until(_Lock& __lock,
343 const chrono::time_point<_Clock, _Duration>& __atime,
347 if (wait_until(__lock, __atime) == cv_status::timeout)
352 template<typename _Lock, typename _Rep, typename _Period>
354 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
355 { return wait_until(__lock, __clock_t::now() + __rtime); }
357 template<typename _Lock, typename _Rep,
358 typename _Period, typename _Predicate>
360 wait_for(_Lock& __lock,
361 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
362 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
364#ifdef __cpp_lib_jthread
365 template <class _Lock, class _Predicate>
366 bool wait(_Lock& __lock,
370 if (__stoken.stop_requested())
375 std::stop_callback __cb(__stoken, [this] { notify_all(); });
376 shared_ptr<mutex> __mutex = _M_mutex;
379 unique_lock<mutex> __my_lock(*__mutex);
380 if (__stoken.stop_requested())
384 // *__mutex must be unlocked before re-locking __lock so move
385 // ownership of *__mutex lock to an object with shorter lifetime.
386 _Unlock<_Lock> __unlock(__lock);
387 unique_lock<mutex> __my_lock2(std::move(__my_lock));
388 _M_cond.wait(__my_lock2);
393 template <class _Lock, class _Clock, class _Duration, class _Predicate>
394 bool wait_until(_Lock& __lock,
396 const chrono::time_point<_Clock, _Duration>& __abs_time,
399 if (__stoken.stop_requested())
404 std::stop_callback __cb(__stoken, [this] { notify_all(); });
405 shared_ptr<mutex> __mutex = _M_mutex;
410 unique_lock<mutex> __my_lock(*__mutex);
411 if (__stoken.stop_requested())
415 _Unlock<_Lock> __u(__lock);
416 unique_lock<mutex> __my_lock2(std::move(__my_lock));
417 const auto __status = _M_cond.wait_until(__my_lock2, __abs_time);
418 __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested();
428 template <class _Lock, class _Rep, class _Period, class _Predicate>
429 bool wait_for(_Lock& __lock,
431 const chrono::duration<_Rep, _Period>& __rel_time,
434 auto __abst = std::chrono::steady_clock::now() + __rel_time;
435 return wait_until(__lock,
443 } // end inline namespace
445 /// @} group condition_variables
446_GLIBCXX_END_NAMESPACE_VERSION
449#endif // _GLIBCXX_HAS_GTHREADS
451#endif // _GLIBCXX_CONDITION_VARIABLE