Init
This commit is contained in:
484
cppdraft/thread/condition/condvar.md
Normal file
484
cppdraft/thread/condition/condvar.md
Normal file
@@ -0,0 +1,484 @@
|
||||
[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*]
|
||||
462
cppdraft/thread/condition/condvarany.md
Normal file
462
cppdraft/thread/condition/condvarany.md
Normal file
@@ -0,0 +1,462 @@
|
||||
[thread.condition.condvarany]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvarany)
|
||||
|
||||
### 32.7.5 Class condition_variable_any [thread.condition.condvarany]
|
||||
|
||||
#### [32.7.5.1](#general) General [[thread.condition.condvarany.general]](thread.condition.condvarany.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10004)
|
||||
|
||||
In [thread.condition.condvarany],
|
||||
template arguments for template parameters named Lock shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#general-1.sentence-1)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
All of the standard
|
||||
mutex types meet this requirement[.](#general-1.sentence-2)
|
||||
|
||||
If a type other than one of the
|
||||
standard mutex types or a unique_lock wrapper for a standard mutex type
|
||||
is used with condition_variable_any, any
|
||||
necessary synchronization is assumed to be in place with respect to the predicate associated
|
||||
with the condition_variable_any instance[.](#general-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:condition_variable_any)
|
||||
|
||||
namespace std {class condition_variable_any {public: condition_variable_any(); ~condition_variable_any();
|
||||
|
||||
condition_variable_any(const condition_variable_any&) = delete;
|
||||
condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; // [[thread.condvarany.wait]](#thread.condvarany.wait "32.7.5.2 Noninterruptible waits"), noninterruptible waitstemplate<class Lock>void wait(Lock& lock); template<class Lock, class Predicate>void wait(Lock& lock, Predicate pred); template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred); template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); // [[thread.condvarany.intwait]](#thread.condvarany.intwait "32.7.5.3 Interruptible waits"), interruptible waitstemplate<class Lock, class Predicate>bool wait(Lock& lock, stop_token stoken, Predicate pred); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred); };}
|
||||
|
||||
[ð](#lib:condition_variable_any,constructor)
|
||||
|
||||
`condition_variable_any();
|
||||
`
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10067)
|
||||
|
||||
*Throws*: bad_alloc or system_error when an exception is
|
||||
required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#general-2.sentence-1)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10072)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(3.1)](#general-3.1)
|
||||
|
||||
resource_unavailable_try_again â if some non-memory resource
|
||||
limitation prevents initialization[.](#general-3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#general-3.2)
|
||||
|
||||
operation_not_permitted â if the thread does not have the
|
||||
privilege to perform the operation[.](#general-3.2.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable_any,destructor)
|
||||
|
||||
`~condition_variable_any();
|
||||
`
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10089)
|
||||
|
||||
*Preconditions*: There is no thread blocked on *this[.](#general-4.sentence-1)
|
||||
|
||||
[*Note [2](#general-note-2)*:
|
||||
|
||||
That is, all
|
||||
threads have been notified; they can subsequently block on the lock specified in the
|
||||
wait[.](#general-4.sentence-2)
|
||||
|
||||
This relaxes the usual rules, which would have required all wait calls to happen before
|
||||
destruction[.](#general-4.sentence-3)
|
||||
|
||||
Only the notification to unblock the wait needs to happen before destruction[.](#general-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[.](#general-4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:notify_one,condition_variable_any)
|
||||
|
||||
`void notify_one() noexcept;
|
||||
`
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10110)
|
||||
|
||||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#general-5.sentence-1)
|
||||
|
||||
[ð](#lib:notify_all,condition_variable_any)
|
||||
|
||||
`void notify_all() noexcept;
|
||||
`
|
||||
|
||||
[6](#general-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10121)
|
||||
|
||||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#general-6.sentence-1)
|
||||
|
||||
#### [32.7.5.2](#thread.condvarany.wait) Noninterruptible waits [[thread.condvarany.wait]](thread.condvarany.wait)
|
||||
|
||||
[ð](#lib:wait,condition_variable_any)
|
||||
|
||||
`template<class Lock>
|
||||
void wait(Lock& lock);
|
||||
`
|
||||
|
||||
[1](#thread.condvarany.wait-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10135)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(1.1)](#thread.condvarany.wait-1.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#thread.condvarany.wait-1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#thread.condvarany.wait-1.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#thread.condvarany.wait-1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#thread.condvarany.wait-1.3)
|
||||
|
||||
The function will unblock when signaled by a call to notify_one(),
|
||||
a call to notify_all(), or spuriously[.](#thread.condvarany.wait-1.3.sentence-1)
|
||||
|
||||
[2](#thread.condvarany.wait-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10145)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-2.sentence-1)
|
||||
|
||||
[3](#thread.condvarany.wait-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10149)
|
||||
|
||||
*Throws*: Nothing[.](#thread.condvarany.wait-3.sentence-1)
|
||||
|
||||
[4](#thread.condvarany.wait-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10153)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-4.sentence-1)
|
||||
|
||||
[*Note [1](#thread.condvarany.wait-note-1)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Predicate>
|
||||
void wait(Lock& lock, Predicate pred);
|
||||
`
|
||||
|
||||
[5](#thread.condvarany.wait-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10169)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred()) wait(lock);
|
||||
|
||||
[ð](#lib:wait_until,condition_variable_any)
|
||||
|
||||
`template<class Lock, class Clock, class Duration>
|
||||
cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
|
||||
`
|
||||
|
||||
[6](#thread.condvarany.wait-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10185)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(6.1)](#thread.condvarany.wait-6.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#thread.condvarany.wait-6.1.sentence-1)
|
||||
|
||||
- [(6.2)](#thread.condvarany.wait-6.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#thread.condvarany.wait-6.2.sentence-1)
|
||||
|
||||
- [(6.3)](#thread.condvarany.wait-6.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[.](#thread.condvarany.wait-6.3.sentence-1)
|
||||
|
||||
- [(6.4)](#thread.condvarany.wait-6.4)
|
||||
|
||||
If the function exits via an exception, lock.lock() is called prior to exiting the function[.](#thread.condvarany.wait-6.4.sentence-1)
|
||||
|
||||
[7](#thread.condvarany.wait-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10204)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-7.sentence-1)
|
||||
|
||||
[8](#thread.condvarany.wait-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10208)
|
||||
|
||||
*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[.](#thread.condvarany.wait-8.sentence-1)
|
||||
|
||||
[9](#thread.condvarany.wait-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10214)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#thread.condvarany.wait-9.sentence-1)
|
||||
|
||||
[10](#thread.condvarany.wait-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10219)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-10.sentence-1)
|
||||
|
||||
[*Note [2](#thread.condvarany.wait-note-2)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable_any)
|
||||
|
||||
`template<class Lock, class Rep, class Period>
|
||||
cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
|
||||
`
|
||||
|
||||
[11](#thread.condvarany.wait-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10235)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time);
|
||||
|
||||
[12](#thread.condvarany.wait-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10242)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-12.sentence-1)
|
||||
|
||||
[13](#thread.condvarany.wait-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10246)
|
||||
|
||||
*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[.](#thread.condvarany.wait-13.sentence-1)
|
||||
|
||||
[14](#thread.condvarany.wait-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10252)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#thread.condvarany.wait-14.sentence-1)
|
||||
|
||||
[15](#thread.condvarany.wait-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10257)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-15.sentence-1)
|
||||
|
||||
[*Note [3](#thread.condvarany.wait-note-3)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-15.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_until,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
|
||||
`
|
||||
|
||||
[16](#thread.condvarany.wait-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10273)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred())if (wait_until(lock, abs_time) == cv_status::timeout)return pred();return true;
|
||||
|
||||
[17](#thread.condvarany.wait-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10283)
|
||||
|
||||
[*Note [4](#thread.condvarany.wait-note-4)*:
|
||||
|
||||
There is no blocking if pred() is initially true, or
|
||||
if the timeout has already expired[.](#thread.condvarany.wait-17.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#thread.condvarany.wait-18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10289)
|
||||
|
||||
[*Note [5](#thread.condvarany.wait-note-5)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered[.](#thread.condvarany.wait-18.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Rep, class Period, class Predicate>
|
||||
bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
|
||||
`
|
||||
|
||||
[19](#thread.condvarany.wait-19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10303)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||
|
||||
#### [32.7.5.3](#thread.condvarany.intwait) Interruptible waits [[thread.condvarany.intwait]](thread.condvarany.intwait)
|
||||
|
||||
[1](#thread.condvarany.intwait-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10313)
|
||||
|
||||
The following wait functions will be notified
|
||||
when there is a stop request on the passed stop_token[.](#thread.condvarany.intwait-1.sentence-1)
|
||||
|
||||
In that case the functions return immediately,
|
||||
returning false if the predicate evaluates to false[.](#thread.condvarany.intwait-1.sentence-2)
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:1)
|
||||
|
||||
`template<class Lock, class Predicate>
|
||||
bool wait(Lock& lock, stop_token stoken, Predicate pred);
|
||||
`
|
||||
|
||||
[2](#thread.condvarany.intwait-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10325)
|
||||
|
||||
*Effects*: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to:while (!stoken.stop_requested()) {if (pred())return true;
|
||||
wait(lock);}return pred();
|
||||
|
||||
[3](#thread.condvarany.intwait-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10339)
|
||||
|
||||
[*Note [1](#thread.condvarany.intwait-note-1)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluated totrue regardless of whether there was a stop request[.](#thread.condvarany.intwait-3.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#thread.condvarany.intwait-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10345)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.intwait-4.sentence-1)
|
||||
|
||||
[5](#thread.condvarany.intwait-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10349)
|
||||
|
||||
*Throws*: Any exception thrown by pred[.](#thread.condvarany.intwait-5.sentence-1)
|
||||
|
||||
[6](#thread.condvarany.intwait-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10353)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition,terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.intwait-6.sentence-1)
|
||||
|
||||
[*Note [2](#thread.condvarany.intwait-note-2)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.intwait-6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:2)
|
||||
|
||||
`template<class Lock, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(Lock& lock, stop_token stoken,
|
||||
const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
|
||||
`
|
||||
|
||||
[7](#thread.condvarany.intwait-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10369)
|
||||
|
||||
*Effects*: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to:while (!stoken.stop_requested()) {if (pred())return true; if (wait_until(lock, abs_time) == cv_status::timeout)return pred();}return pred();
|
||||
|
||||
[8](#thread.condvarany.intwait-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10384)
|
||||
|
||||
[*Note [3](#thread.condvarany.intwait-note-3)*:
|
||||
|
||||
There is no blocking if pred() is initially true,stoken.stop_requested() was already true or the timeout has already expired[.](#thread.condvarany.intwait-8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#thread.condvarany.intwait-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10391)
|
||||
|
||||
[*Note [4](#thread.condvarany.intwait-note-4)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluated to true regardless of whether the timeout was triggered or a stop request was made[.](#thread.condvarany.intwait-9.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#thread.condvarany.intwait-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10397)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.intwait-10.sentence-1)
|
||||
|
||||
[11](#thread.condvarany.intwait-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10401)
|
||||
|
||||
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")),
|
||||
or any exception thrown by pred[.](#thread.condvarany.intwait-11.sentence-1)
|
||||
|
||||
[12](#thread.condvarany.intwait-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10406)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition,terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.intwait-12.sentence-1)
|
||||
|
||||
[*Note [5](#thread.condvarany.intwait-note-5)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.intwait-12.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:3)
|
||||
|
||||
`template<class Lock, class Rep, class Period, class Predicate>
|
||||
bool wait_for(Lock& lock, stop_token stoken,
|
||||
const chrono::duration<Rep, Period>& rel_time, Predicate pred);
|
||||
`
|
||||
|
||||
[13](#thread.condvarany.intwait-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10422)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time,
|
||||
std::move(pred));
|
||||
115
cppdraft/thread/condition/condvarany/general.md
Normal file
115
cppdraft/thread/condition/condvarany/general.md
Normal file
@@ -0,0 +1,115 @@
|
||||
[thread.condition.condvarany.general]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvarany.general)
|
||||
|
||||
### 32.7.5 Class condition_variable_any [[thread.condition.condvarany]](thread.condition.condvarany#general)
|
||||
|
||||
#### 32.7.5.1 General [thread.condition.condvarany.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10004)
|
||||
|
||||
In [[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_variable_any"),
|
||||
template arguments for template parameters named Lock shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
All of the standard
|
||||
mutex types meet this requirement[.](#1.sentence-2)
|
||||
|
||||
If a type other than one of the
|
||||
standard mutex types or a unique_lock wrapper for a standard mutex type
|
||||
is used with condition_variable_any, any
|
||||
necessary synchronization is assumed to be in place with respect to the predicate associated
|
||||
with the condition_variable_any instance[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:condition_variable_any)
|
||||
|
||||
namespace std {class condition_variable_any {public: condition_variable_any(); ~condition_variable_any();
|
||||
|
||||
condition_variable_any(const condition_variable_any&) = delete;
|
||||
condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; // [[thread.condvarany.wait]](thread.condvarany.wait "32.7.5.2 Noninterruptible waits"), noninterruptible waitstemplate<class Lock>void wait(Lock& lock); template<class Lock, class Predicate>void wait(Lock& lock, Predicate pred); template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred); template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); // [[thread.condvarany.intwait]](thread.condvarany.intwait "32.7.5.3 Interruptible waits"), interruptible waitstemplate<class Lock, class Predicate>bool wait(Lock& lock, stop_token stoken, Predicate pred); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred); };}
|
||||
|
||||
[ð](#lib:condition_variable_any,constructor)
|
||||
|
||||
`condition_variable_any();
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10067)
|
||||
|
||||
*Throws*: bad_alloc or 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#L10072)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
resource_unavailable_try_again â if some non-memory resource
|
||||
limitation prevents initialization[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
operation_not_permitted â if the thread does not have the
|
||||
privilege to perform the operation[.](#3.2.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable_any,destructor)
|
||||
|
||||
`~condition_variable_any();
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10089)
|
||||
|
||||
*Preconditions*: There is no thread blocked on *this[.](#4.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
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_any)
|
||||
|
||||
`void notify_one() noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10110)
|
||||
|
||||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#5.sentence-1)
|
||||
|
||||
[ð](#lib:notify_all,condition_variable_any)
|
||||
|
||||
`void notify_all() noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10121)
|
||||
|
||||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#6.sentence-1)
|
||||
56
cppdraft/thread/condition/general.md
Normal file
56
cppdraft/thread/condition/general.md
Normal file
@@ -0,0 +1,56 @@
|
||||
[thread.condition.general]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#general)
|
||||
|
||||
### 32.7.1 General [thread.condition.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9482)
|
||||
|
||||
Condition variables provide synchronization primitives used to block a thread until
|
||||
notified by some other thread that some condition is met or until a system time is
|
||||
reached[.](#1.sentence-1)
|
||||
|
||||
Class condition_variable provides a condition variable that can only
|
||||
wait on an object of type unique_lock<mutex>, allowing the implementation
|
||||
to be more efficient[.](#1.sentence-2)
|
||||
|
||||
Class condition_variable_any provides a general
|
||||
condition variable that can wait on objects of user-supplied lock types[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9490)
|
||||
|
||||
Condition variables permit concurrent invocation of the wait, wait_for,wait_until, notify_one and notify_all member functions[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9494)
|
||||
|
||||
The executions of notify_one and notify_all are atomic[.](#3.sentence-1)
|
||||
|
||||
The executions of wait, wait_for, and wait_until are performed
|
||||
in three atomic parts:
|
||||
|
||||
| [1.](#3.1) | the release of the mutex and entry into the waiting state; |
|
||||
| --- | --- |
|
||||
| [2.](#3.2) | the unblocking of the wait; and |
|
||||
| [3.](#3.3) | the reacquisition of the lock[.](#3.sentence-2) |
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9505)
|
||||
|
||||
The implementation behaves as if all executions of notify_one, notify_all, and each
|
||||
part of the wait, wait_for, and wait_until executions are
|
||||
executed in a single unspecified total order consistent with the âhappens beforeâ order[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9510)
|
||||
|
||||
Condition variable construction and destruction need not be synchronized[.](#5.sentence-1)
|
||||
74
cppdraft/thread/condition/nonmember.md
Normal file
74
cppdraft/thread/condition/nonmember.md
Normal file
@@ -0,0 +1,74 @@
|
||||
[thread.condition.nonmember]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#nonmember)
|
||||
|
||||
### 32.7.3 Non-member functions [thread.condition.nonmember]
|
||||
|
||||
[ð](#lib:notify_all_at_thread_exit)
|
||||
|
||||
`void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9537)
|
||||
|
||||
*Preconditions*: lk is locked by the calling thread and either
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
no other thread is waiting on cond, or
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
lk.mutex() returns the same value for each of the lock arguments
|
||||
supplied by all concurrently waiting (via wait, wait_for,
|
||||
or wait_until) threads[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9547)
|
||||
|
||||
*Effects*: Transfers ownership of the lock associated with lk into
|
||||
internal storage and schedules cond to be notified when the current
|
||||
thread exits, after all objects with thread storage duration associated with
|
||||
the current thread have been destroyed[.](#2.sentence-1)
|
||||
|
||||
This notification is equivalent to:lk.unlock();
|
||||
cond.notify_all();
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9558)
|
||||
|
||||
*Synchronization*: The implied lk.unlock() call is sequenced after the destruction of
|
||||
all objects with thread storage duration associated with the current thread[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9563)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The supplied lock is held until the thread exits,
|
||||
which might cause deadlock due to lock ordering issues[.](#4.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9569)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
It is the user's responsibility to ensure that waiting threads
|
||||
do not incorrectly assume that the thread has finished if they experience
|
||||
spurious wakeups[.](#5.sentence-1)
|
||||
|
||||
This typically requires that the condition being waited
|
||||
for is satisfied while holding the lock on lk, and that this lock
|
||||
is not released and reacquired prior to calling notify_all_at_thread_exit[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
Reference in New Issue
Block a user