485 lines
17 KiB
Markdown
485 lines
17 KiB
Markdown
[thread.condition.condvar]
|
||
|
||
# 32 Concurrency support library [[thread]](./#thread)
|
||
|
||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvar)
|
||
|
||
### 32.7.4 Class condition_variable [thread.condition.condvar]
|
||
|
||
[ð](#lib:condition_variable)
|
||
|
||
namespace std {class condition_variable {public: condition_variable(); ~condition_variable();
|
||
|
||
condition_variable(const condition_variable&) = delete;
|
||
condition_variable& operator=(const condition_variable&) = delete; void notify_one() noexcept; void notify_all() noexcept; void wait(unique_lock<mutex>& lock); template<class Predicate>void wait(unique_lock<mutex>& lock, Predicate pred); template<class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Clock, class Duration, class Predicate>bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||
Predicate pred); template<class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time); template<class Rep, class Period, class Predicate>bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time,
|
||
Predicate pred); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9618)
|
||
|
||
The class condition_variable is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#1.sentence-1)
|
||
|
||
[ð](#lib:condition_variable,constructor)
|
||
|
||
`condition_variable();
|
||
`
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9627)
|
||
|
||
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#2.sentence-1)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9631)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(3.1)](#3.1)
|
||
|
||
resource_unavailable_try_again â if some non-memory resource
|
||
limitation prevents initialization[.](#3.sentence-1)
|
||
|
||
[ð](#lib:condition_variable,destructor)
|
||
|
||
`~condition_variable();
|
||
`
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9645)
|
||
|
||
*Preconditions*: There is no thread blocked on *this[.](#4.sentence-1)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
That is, all
|
||
threads have been notified; they can subsequently block on the lock specified in the
|
||
wait[.](#4.sentence-2)
|
||
|
||
This relaxes the usual rules, which would have required all wait calls to happen before
|
||
destruction[.](#4.sentence-3)
|
||
|
||
Only the notification to unblock the wait needs to happen before destruction[.](#4.sentence-4)
|
||
|
||
Undefined behavior ensues if a thread waits on *this once the destructor has
|
||
been started, especially when the waiting threads are calling the wait functions in a loop or
|
||
using the overloads of wait, wait_for, or wait_until that take a predicate[.](#4.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:notify_one,condition_variable)
|
||
|
||
`void notify_one() noexcept;
|
||
`
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9666)
|
||
|
||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#5.sentence-1)
|
||
|
||
[ð](#lib:notify_all,condition_variable)
|
||
|
||
`void notify_all() noexcept;
|
||
`
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9677)
|
||
|
||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#6.sentence-1)
|
||
|
||
[ð](#lib:wait,condition_variable)
|
||
|
||
`void wait(unique_lock<mutex>& lock);
|
||
`
|
||
|
||
[7](#7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9688)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||
|
||
- [(7.1)](#7.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(7.2)](#7.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#7.sentence-1)
|
||
|
||
[8](#8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9699)
|
||
|
||
*Effects*:
|
||
|
||
- [(8.1)](#8.1)
|
||
|
||
Atomically calls lock.unlock() and blocks on *this[.](#8.1.sentence-1)
|
||
|
||
- [(8.2)](#8.2)
|
||
|
||
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns[.](#8.2.sentence-1)
|
||
|
||
- [(8.3)](#8.3)
|
||
|
||
The function will unblock when signaled by a call to notify_one() or a call to notify_all(), or spuriously[.](#8.3.sentence-1)
|
||
|
||
[9](#9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9709)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#9.sentence-1)
|
||
|
||
[10](#10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9714)
|
||
|
||
*Throws*: Nothing[.](#10.sentence-1)
|
||
|
||
[11](#11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9718)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#11.sentence-1)
|
||
|
||
[*Note [2](#note-2)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#11.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait,condition_variable_)
|
||
|
||
`template<class Predicate>
|
||
void wait(unique_lock<mutex>& lock, Predicate pred);
|
||
`
|
||
|
||
[12](#12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9734)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is
|
||
locked by the calling thread, and either
|
||
|
||
- [(12.1)](#12.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(12.2)](#12.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#12.sentence-1)
|
||
|
||
[13](#13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9745)
|
||
|
||
*Effects*: Equivalent to:while (!pred()) wait(lock);
|
||
|
||
[14](#14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9753)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#14.sentence-1)
|
||
|
||
[15](#15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9758)
|
||
|
||
*Throws*: Any exception thrown by pred[.](#15.sentence-1)
|
||
|
||
[16](#16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9762)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#16.sentence-1)
|
||
|
||
[*Note [3](#note-3)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#16.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait_until,condition_variable)
|
||
|
||
`template<class Clock, class Duration>
|
||
cv_status wait_until(unique_lock<mutex>& lock,
|
||
const chrono::time_point<Clock, Duration>& abs_time);
|
||
`
|
||
|
||
[17](#17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9779)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||
|
||
- [(17.1)](#17.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(17.2)](#17.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#17.sentence-1)
|
||
|
||
[18](#18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9790)
|
||
|
||
*Effects*:
|
||
|
||
- [(18.1)](#18.1)
|
||
|
||
Atomically calls lock.unlock() and blocks on *this[.](#18.1.sentence-1)
|
||
|
||
- [(18.2)](#18.2)
|
||
|
||
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns[.](#18.2.sentence-1)
|
||
|
||
- [(18.3)](#18.3)
|
||
|
||
The function will unblock when signaled by a call to notify_one(), a call to notify_all(),
|
||
expiration of the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time,
|
||
or spuriously[.](#18.3.sentence-1)
|
||
|
||
- [(18.4)](#18.4)
|
||
|
||
If the function exits via an exception, lock.lock() is called prior to exiting the function[.](#18.4.sentence-1)
|
||
|
||
[19](#19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9808)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#19.sentence-1)
|
||
|
||
[20](#20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9813)
|
||
|
||
*Returns*: cv_status::timeout if
|
||
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time expired,
|
||
otherwise cv_status::no_timeout[.](#20.sentence-1)
|
||
|
||
[21](#21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9819)
|
||
|
||
*Throws*: Timeout-related
|
||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#21.sentence-1)
|
||
|
||
[22](#22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9824)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#22.sentence-1)
|
||
|
||
[*Note [4](#note-4)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#22.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait_for,condition_variable)
|
||
|
||
`template<class Rep, class Period>
|
||
cv_status wait_for(unique_lock<mutex>& lock,
|
||
const chrono::duration<Rep, Period>& rel_time);
|
||
`
|
||
|
||
[23](#23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9841)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||
|
||
- [(23.1)](#23.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(23.2)](#23.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments
|
||
supplied by all concurrently waiting (via wait, wait_for, orwait_until) threads[.](#23.sentence-1)
|
||
|
||
[24](#24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9852)
|
||
|
||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time);
|
||
|
||
[25](#25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9859)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#25.sentence-1)
|
||
|
||
[26](#26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9864)
|
||
|
||
*Returns*: cv_status::timeout if
|
||
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by rel_time expired,
|
||
otherwise cv_status::no_timeout[.](#26.sentence-1)
|
||
|
||
[27](#27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9870)
|
||
|
||
*Throws*: Timeout-related
|
||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#27.sentence-1)
|
||
|
||
[28](#28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9875)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#28.sentence-1)
|
||
|
||
[*Note [5](#note-5)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#28.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait_until,condition_variable_)
|
||
|
||
`template<class Clock, class Duration, class Predicate>
|
||
bool wait_until(unique_lock<mutex>& lock,
|
||
const chrono::time_point<Clock, Duration>& abs_time,
|
||
Predicate pred);
|
||
`
|
||
|
||
[29](#29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9893)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is
|
||
locked by the calling thread, and either
|
||
|
||
- [(29.1)](#29.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(29.2)](#29.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#29.sentence-1)
|
||
|
||
[30](#30)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9904)
|
||
|
||
*Effects*: Equivalent to:while (!pred())if (wait_until(lock, abs_time) == cv_status::timeout)return pred();return true;
|
||
|
||
[31](#31)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9914)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#31.sentence-1)
|
||
|
||
[32](#32)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9919)
|
||
|
||
[*Note [6](#note-6)*:
|
||
|
||
The returned value indicates whether the predicate evaluated totrue regardless of whether the timeout was triggered[.](#32.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[33](#33)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9925)
|
||
|
||
*Throws*: Timeout-related
|
||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) or any exception thrown by pred[.](#33.sentence-1)
|
||
|
||
[34](#34)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9930)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#34.sentence-1)
|
||
|
||
[*Note [7](#note-7)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#34.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait_for,condition_variable_)
|
||
|
||
`template<class Rep, class Period, class Predicate>
|
||
bool wait_for(unique_lock<mutex>& lock,
|
||
const chrono::duration<Rep, Period>& rel_time,
|
||
Predicate pred);
|
||
`
|
||
|
||
[35](#35)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9948)
|
||
|
||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||
|
||
- [(35.1)](#35.1)
|
||
|
||
no other thread is waiting on this condition_variable object or
|
||
|
||
- [(35.2)](#35.2)
|
||
|
||
lock.mutex() returns the same value for each of the lock arguments
|
||
supplied by all concurrently waiting (via wait, wait_for, orwait_until) threads[.](#35.sentence-1)
|
||
|
||
[36](#36)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9962)
|
||
|
||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
|
||
|
||
[37](#37)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9969)
|
||
|
||
[*Note [8](#note-8)*:
|
||
|
||
There is no blocking if pred() is initially true, even if the
|
||
timeout has already expired[.](#37.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[38](#38)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9975)
|
||
|
||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#38.sentence-1)
|
||
|
||
[39](#39)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9980)
|
||
|
||
[*Note [9](#note-9)*:
|
||
|
||
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered[.](#39.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[40](#40)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9986)
|
||
|
||
*Throws*: Timeout-related
|
||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) or any exception thrown by pred[.](#40.sentence-1)
|
||
|
||
[41](#41)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9991)
|
||
|
||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#41.sentence-1)
|
||
|
||
[*Note [10](#note-10)*:
|
||
|
||
This can happen if the re-locking of the mutex throws an exception[.](#41.sentence-2)
|
||
|
||
â *end note*]
|