This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

334
cppdraft/thread/barrier.md Normal file
View File

@@ -0,0 +1,334 @@
[thread.barrier]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.barrier)
### 32.9.3 Barriers [thread.barrier]
#### [32.9.3.1](#general) General [[thread.barrier.general]](thread.barrier.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10845)
A barrier is a thread coordination mechanism
whose lifetime consists of a sequence of barrier phases,
where each phase allows at most an expected number of threads to block
until the expected number of threads arrive at the barrier[.](#general-1.sentence-1)
[*Note [1](#general-note-1)*:
A barrier is useful for managing repeated tasks
that are handled by multiple threads[.](#general-1.sentence-2)
— *end note*]
#### [32.9.3.2](#barrier.syn) Header <barrier> synopsis [[barrier.syn]](barrier.syn)
[🔗](#header:%3cbarrier%3e)
namespace std {template<class CompletionFunction = *see below*>class barrier;}
#### [32.9.3.3](#class) Class template barrier [[thread.barrier.class]](thread.barrier.class)
namespace std {template<class CompletionFunction = *see below*>class barrier {public:using arrival_token = *see below*; static constexpr ptrdiff_t max() noexcept; constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction()); ~barrier();
barrier(const barrier&) = delete;
barrier& operator=(const barrier&) = delete;
arrival_token arrive(ptrdiff_t update = 1); void wait(arrival_token&& arrival) const; void arrive_and_wait(); void arrive_and_drop(); private: CompletionFunction completion; // *exposition only*};}
[1](#class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10895)
Each [*barrier phase*](#def:barrier_phase "32.9.3.3Class template barrier[thread.barrier.class]") consists of the following steps:
- [(1.1)](#class-1.1)
The expected count is decremented
by each call to arrive or arrive_and_drop[.](#class-1.1.sentence-1)
- [(1.2)](#class-1.2)
Exactly once after the expected count reaches zero, a thread
executes the completion step during its call
to arrive, arrive_and_drop, or wait,
except that it is implementation-defined
whether the step executes if no thread calls wait[.](#class-1.2.sentence-1)
- [(1.3)](#class-1.3)
When the completion step finishes,
the expected count is reset
to what was specified by the expected argument to the constructor,
possibly adjusted by calls to arrive_and_drop, and
the next phase starts[.](#class-1.3.sentence-1)
[2](#class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10916)
Each phase defines a [*phase synchronization point*](#def:barrier,phase_synchronization_point "32.9.3.3Class template barrier[thread.barrier.class]")[.](#class-2.sentence-1)
Threads that arrive at the barrier during the phase
can block on the phase synchronization point by calling wait, and
will remain blocked until the phase completion step is run[.](#class-2.sentence-2)
[3](#class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10923)
The [*phase completion step*](#def:phase_completion_step "32.9.3.3Class template barrier[thread.barrier.class]") that is executed at the end of each phase has the following effects:
- [(3.1)](#class-3.1)
Invokes the completion function, equivalent to completion()[.](#class-3.1.sentence-1)
- [(3.2)](#class-3.2)
Unblocks all threads that are blocked on the phase synchronization point[.](#class-3.2.sentence-1)
The end of the completion step strongly happens before
the returns from all calls that were unblocked by the completion step[.](#class-3.sentence-2)
For specializations that do not have
the default value of the CompletionFunction template parameter,
the behavior is undefined if any of the barrier object's member functions
other than wait are called while the completion step is in progress[.](#class-3.sentence-3)
[4](#class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10937)
Concurrent invocations of the member functions of barrier,
other than its destructor, do not introduce data races[.](#class-4.sentence-1)
The member functions arrive and arrive_and_drop execute atomically[.](#class-4.sentence-2)
[5](#class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10943)
CompletionFunction shall meet the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")) and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#class-5.sentence-1)
is_nothrow_invocable_v<CompletionFunction&> shall be true[.](#class-5.sentence-2)
[6](#class-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10949)
The default value of the CompletionFunction template parameter is
an unspecified type, such that,
in addition to satisfying the requirements of CompletionFunction,
it meets the [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") requirements (Table [30](utility.arg.requirements#tab:cpp17.defaultconstructible "Table 30: Cpp17DefaultConstructible requirements")) andcompletion() has no effects[.](#class-6.sentence-1)
[7](#class-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10957)
barrier::arrival_token is an unspecified type,
such that it meets the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")),[*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [33](utility.arg.requirements#tab:cpp17.moveassignable "Table 33: Cpp17MoveAssignable requirements")), and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#class-7.sentence-1)
[🔗](#lib:max,barrier)
`static constexpr ptrdiff_t max() noexcept;
`
[8](#class-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10970)
*Returns*: The maximum expected count that the implementation supports[.](#class-8.sentence-1)
[🔗](#lib:barrier,constructor)
`constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction());
`
[9](#class-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10982)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#class-9.sentence-1)
[10](#class-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10987)
*Effects*: Sets both the initial expected count for each barrier phase and
the current expected count for the first phase to expected[.](#class-10.sentence-1)
Initializes completion with std::move(f)[.](#class-10.sentence-2)
Starts the first phase[.](#class-10.sentence-3)
[*Note [1](#class-note-1)*:
If expected is 0 this object can only be destroyed[.](#class-10.sentence-4)
— *end note*]
[11](#class-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10997)
*Throws*: Any exception thrown by CompletionFunction's move constructor[.](#class-11.sentence-1)
[🔗](#lib:arrive,barrier)
`arrival_token arrive(ptrdiff_t update = 1);
`
[12](#class-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11008)
*Preconditions*: update > 0 is true, andupdate is less than or equal to
the expected count for the current barrier phase[.](#class-12.sentence-1)
[13](#class-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11014)
*Effects*: Constructs an object of type arrival_token that is associated with the phase synchronization point for the current phase[.](#class-13.sentence-1)
Then, decrements the expected count by update[.](#class-13.sentence-2)
[14](#class-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11020)
*Synchronization*: The call to arrive strongly happens before
the start of the phase completion step for the current phase[.](#class-14.sentence-1)
[15](#class-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11025)
*Returns*: The constructed arrival_token object[.](#class-15.sentence-1)
[16](#class-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11029)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#class-16.sentence-1)
[17](#class-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11033)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#class-17.sentence-1)
[18](#class-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11038)
[*Note [2](#class-note-2)*:
This call can cause the completion step for the current phase to start[.](#class-18.sentence-1)
— *end note*]
[🔗](#lib:wait,barrier)
`void wait(arrival_token&& arrival) const;
`
[19](#class-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11050)
*Preconditions*: arrival is associated with
the phase synchronization point for the current phase or
the immediately preceding phase of the same barrier object[.](#class-19.sentence-1)
[20](#class-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11056)
*Effects*: Blocks at the synchronization point associated with std::move(arrival) until the phase completion step of the synchronization point's phase is run[.](#class-20.sentence-1)
[*Note [3](#class-note-3)*:
If arrival is associated with the synchronization point
for a previous phase, the call returns immediately[.](#class-20.sentence-2)
— *end note*]
[21](#class-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11066)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#class-21.sentence-1)
[22](#class-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11070)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#class-22.sentence-1)
[🔗](#lib:arrive_and_wait,barrier)
`void arrive_and_wait();
`
[23](#class-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11082)
*Effects*: Equivalent to: wait(arrive())[.](#class-23.sentence-1)
[🔗](#lib:arrive_and_drop,barrier)
`void arrive_and_drop();
`
[24](#class-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11093)
*Preconditions*: The expected count for the current barrier phase is greater than zero[.](#class-24.sentence-1)
[25](#class-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11097)
*Effects*: Decrements the initial expected count for all subsequent phases by one[.](#class-25.sentence-1)
Then decrements the expected count for the current phase by one[.](#class-25.sentence-2)
[26](#class-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11102)
*Synchronization*: The call to arrive_and_drop strongly happens before
the start of the phase completion step for the current phase[.](#class-26.sentence-1)
[27](#class-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11107)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#class-27.sentence-1)
[28](#class-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11111)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#class-28.sentence-1)
[29](#class-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11116)
[*Note [4](#class-note-4)*:
This call can cause the completion step for the current phase to start[.](#class-29.sentence-1)
— *end note*]

View File

@@ -0,0 +1,310 @@
[thread.barrier.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.barrier.class)
### 32.9.3 Barriers [[thread.barrier]](thread.barrier#class)
#### 32.9.3.3 Class template barrier [thread.barrier.class]
namespace std {template<class CompletionFunction = *see below*>class barrier {public:using arrival_token = *see below*; static constexpr ptrdiff_t max() noexcept; constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction()); ~barrier();
barrier(const barrier&) = delete;
barrier& operator=(const barrier&) = delete;
arrival_token arrive(ptrdiff_t update = 1); void wait(arrival_token&& arrival) const; void arrive_and_wait(); void arrive_and_drop(); private: CompletionFunction completion; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10895)
Each [*barrier phase*](#def:barrier_phase "32.9.3.3Class template barrier[thread.barrier.class]") consists of the following steps:
- [(1.1)](#1.1)
The expected count is decremented
by each call to arrive or arrive_and_drop[.](#1.1.sentence-1)
- [(1.2)](#1.2)
Exactly once after the expected count reaches zero, a thread
executes the completion step during its call
to arrive, arrive_and_drop, or wait,
except that it is implementation-defined
whether the step executes if no thread calls wait[.](#1.2.sentence-1)
- [(1.3)](#1.3)
When the completion step finishes,
the expected count is reset
to what was specified by the expected argument to the constructor,
possibly adjusted by calls to arrive_and_drop, and
the next phase starts[.](#1.3.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10916)
Each phase defines a [*phase synchronization point*](#def:barrier,phase_synchronization_point "32.9.3.3Class template barrier[thread.barrier.class]")[.](#2.sentence-1)
Threads that arrive at the barrier during the phase
can block on the phase synchronization point by calling wait, and
will remain blocked until the phase completion step is run[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10923)
The [*phase completion step*](#def:phase_completion_step "32.9.3.3Class template barrier[thread.barrier.class]") that is executed at the end of each phase has the following effects:
- [(3.1)](#3.1)
Invokes the completion function, equivalent to completion()[.](#3.1.sentence-1)
- [(3.2)](#3.2)
Unblocks all threads that are blocked on the phase synchronization point[.](#3.2.sentence-1)
The end of the completion step strongly happens before
the returns from all calls that were unblocked by the completion step[.](#3.sentence-2)
For specializations that do not have
the default value of the CompletionFunction template parameter,
the behavior is undefined if any of the barrier object's member functions
other than wait are called while the completion step is in progress[.](#3.sentence-3)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10937)
Concurrent invocations of the member functions of barrier,
other than its destructor, do not introduce data races[.](#4.sentence-1)
The member functions arrive and arrive_and_drop execute atomically[.](#4.sentence-2)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10943)
CompletionFunction shall meet the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")) and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#5.sentence-1)
is_nothrow_invocable_v<CompletionFunction&> shall be true[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10949)
The default value of the CompletionFunction template parameter is
an unspecified type, such that,
in addition to satisfying the requirements of CompletionFunction,
it meets the [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") requirements (Table [30](utility.arg.requirements#tab:cpp17.defaultconstructible "Table 30: Cpp17DefaultConstructible requirements")) andcompletion() has no effects[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10957)
barrier::arrival_token is an unspecified type,
such that it meets the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")),[*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [33](utility.arg.requirements#tab:cpp17.moveassignable "Table 33: Cpp17MoveAssignable requirements")), and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#7.sentence-1)
[🔗](#lib:max,barrier)
`static constexpr ptrdiff_t max() noexcept;
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10970)
*Returns*: The maximum expected count that the implementation supports[.](#8.sentence-1)
[🔗](#lib:barrier,constructor)
`constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction());
`
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10982)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10987)
*Effects*: Sets both the initial expected count for each barrier phase and
the current expected count for the first phase to expected[.](#10.sentence-1)
Initializes completion with std::move(f)[.](#10.sentence-2)
Starts the first phase[.](#10.sentence-3)
[*Note [1](#note-1)*:
If expected is 0 this object can only be destroyed[.](#10.sentence-4)
— *end note*]
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10997)
*Throws*: Any exception thrown by CompletionFunction's move constructor[.](#11.sentence-1)
[🔗](#lib:arrive,barrier)
`arrival_token arrive(ptrdiff_t update = 1);
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11008)
*Preconditions*: update > 0 is true, andupdate is less than or equal to
the expected count for the current barrier phase[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11014)
*Effects*: Constructs an object of type arrival_token that is associated with the phase synchronization point for the current phase[.](#13.sentence-1)
Then, decrements the expected count by update[.](#13.sentence-2)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11020)
*Synchronization*: The call to arrive strongly happens before
the start of the phase completion step for the current phase[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11025)
*Returns*: The constructed arrival_token object[.](#15.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11029)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#16.sentence-1)
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11033)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#17.sentence-1)
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11038)
[*Note [2](#note-2)*:
This call can cause the completion step for the current phase to start[.](#18.sentence-1)
— *end note*]
[🔗](#lib:wait,barrier)
`void wait(arrival_token&& arrival) const;
`
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11050)
*Preconditions*: arrival is associated with
the phase synchronization point for the current phase or
the immediately preceding phase of the same barrier object[.](#19.sentence-1)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11056)
*Effects*: Blocks at the synchronization point associated with std::move(arrival) until the phase completion step of the synchronization point's phase is run[.](#20.sentence-1)
[*Note [3](#note-3)*:
If arrival is associated with the synchronization point
for a previous phase, the call returns immediately[.](#20.sentence-2)
— *end note*]
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11066)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#21.sentence-1)
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11070)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#22.sentence-1)
[🔗](#lib:arrive_and_wait,barrier)
`void arrive_and_wait();
`
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11082)
*Effects*: Equivalent to: wait(arrive())[.](#23.sentence-1)
[🔗](#lib:arrive_and_drop,barrier)
`void arrive_and_drop();
`
[24](#24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11093)
*Preconditions*: The expected count for the current barrier phase is greater than zero[.](#24.sentence-1)
[25](#25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11097)
*Effects*: Decrements the initial expected count for all subsequent phases by one[.](#25.sentence-1)
Then decrements the expected count for the current phase by one[.](#25.sentence-2)
[26](#26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11102)
*Synchronization*: The call to arrive_and_drop strongly happens before
the start of the phase completion step for the current phase[.](#26.sentence-1)
[27](#27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11107)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#27.sentence-1)
[28](#28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11111)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#28.sentence-1)
[29](#29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11116)
[*Note [4](#note-4)*:
This call can cause the completion step for the current phase to start[.](#29.sentence-1)
— *end note*]

View File

@@ -0,0 +1,25 @@
[thread.barrier.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.barrier.general)
### 32.9.3 Barriers [[thread.barrier]](thread.barrier#general)
#### 32.9.3.1 General [thread.barrier.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10845)
A barrier is a thread coordination mechanism
whose lifetime consists of a sequence of barrier phases,
where each phase allows at most an expected number of threads to block
until the expected number of threads arrive at the barrier[.](#1.sentence-1)
[*Note [1](#note-1)*:
A barrier is useful for managing repeated tasks
that are handled by multiple threads[.](#1.sentence-2)
— *end note*]

1067
cppdraft/thread/condition.md Normal file

File diff suppressed because it is too large Load Diff

View 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.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native 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.2Properties 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.2Exceptions"))[.](#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.2The 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.2The 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.4Timing 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.4Timing 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.4Timing 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.2The 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.4Timing 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.4Timing 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.2The 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.4Timing 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.2The 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.4Timing 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.2The 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*]

View 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.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable 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.2Noninterruptible 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.3Interruptible 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.2Exceptions"))[.](#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.2The 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.4Timing 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.4Timing 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.4Timing 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.2The 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.4Timing 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.4Timing 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.2The 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.2The 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.4Timing 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.2The 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));

View 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.5Class condition_­variable_­any"),
template arguments for template parameters named Lock shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable 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.2Noninterruptible 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.3Interruptible 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.2Exceptions"))[.](#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)

View 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)

View 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*]

View File

@@ -0,0 +1,138 @@
[thread.condvarany.intwait]
# 32 Concurrency support library [[thread]](./#thread)
## 32.7 Condition variables [[thread.condition]](thread.condition#thread.condvarany.intwait)
### 32.7.5 Class condition_variable_any [[thread.condition.condvarany]](thread.condition.condvarany#thread.condvarany.intwait)
#### 32.7.5.3 Interruptible waits [thread.condvarany.intwait]
[1](#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[.](#1.sentence-1)
In that case the functions return immediately,
returning false if the predicate evaluates to false[.](#1.sentence-2)
[🔗](#itemdecl:1)
`template<class Lock, class Predicate>
bool wait(Lock& lock, stop_token stoken, Predicate pred);
`
[2](#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](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10339)
[*Note [1](#note-1)*:
The returned value indicates whether the predicate evaluated totrue regardless of whether there was a stop request[.](#3.sentence-1)
— *end note*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10345)
*Postconditions*: lock is locked by the calling thread[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10349)
*Throws*: Any exception thrown by pred[.](#5.sentence-1)
[6](#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.2The std::terminate function"))[.](#6.sentence-1)
[*Note [2](#note-2)*:
This can happen if the re-locking of the mutex throws an exception[.](#6.sentence-2)
— *end note*]
[🔗](#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](#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](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10384)
[*Note [3](#note-3)*:
There is no blocking if pred() is initially true,stoken.stop_requested() was already true or the timeout has already expired[.](#8.sentence-1)
— *end note*]
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10391)
[*Note [4](#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[.](#9.sentence-1)
— *end note*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10397)
*Postconditions*: lock is locked by the calling thread[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10401)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")),
or any exception thrown by pred[.](#11.sentence-1)
[12](#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.2The std::terminate function"))[.](#12.sentence-1)
[*Note [5](#note-5)*:
This can happen if the re-locking of the mutex throws an exception[.](#12.sentence-2)
— *end note*]
[🔗](#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](#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));

View File

@@ -0,0 +1,223 @@
[thread.condvarany.wait]
# 32 Concurrency support library [[thread]](./#thread)
## 32.7 Condition variables [[thread.condition]](thread.condition#thread.condvarany.wait)
### 32.7.5 Class condition_variable_any [[thread.condition.condvarany]](thread.condition.condvarany#thread.condvarany.wait)
#### 32.7.5.2 Noninterruptible waits [thread.condvarany.wait]
[🔗](#lib:wait,condition_variable_any)
`template<class Lock>
void wait(Lock& lock);
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10135)
*Effects*:
- [(1.1)](#1.1)
Atomically calls lock.unlock() and blocks on *this[.](#1.1.sentence-1)
- [(1.2)](#1.2)
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#1.2.sentence-1)
- [(1.3)](#1.3)
The function will unblock when signaled by a call to notify_one(),
a call to notify_all(), or spuriously[.](#1.3.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10145)
*Postconditions*: lock is locked by the calling thread[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10149)
*Throws*: Nothing[.](#3.sentence-1)
[4](#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.2The std::terminate function"))[.](#4.sentence-1)
[*Note [1](#note-1)*:
This can happen if the re-locking of the mutex throws an exception[.](#4.sentence-2)
— *end note*]
[🔗](#lib:wait,condition_variable_any_)
`template<class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
`
[5](#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](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10185)
*Effects*:
- [(6.1)](#6.1)
Atomically calls lock.unlock() and blocks on *this[.](#6.1.sentence-1)
- [(6.2)](#6.2)
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#6.2.sentence-1)
- [(6.3)](#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.4Timing specifications")) specified by abs_time,
or spuriously[.](#6.3.sentence-1)
- [(6.4)](#6.4)
If the function exits via an exception, lock.lock() is called prior to exiting the function[.](#6.4.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10204)
*Postconditions*: lock is locked by the calling thread[.](#7.sentence-1)
[8](#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.4Timing specifications")) specified by abs_time expired,
otherwise cv_status::no_timeout[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10214)
*Throws*: Timeout-related
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#9.sentence-1)
[10](#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.2The std::terminate function"))[.](#10.sentence-1)
[*Note [2](#note-2)*:
This can happen if the re-locking of the mutex throws an exception[.](#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](#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](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10242)
*Postconditions*: lock is locked by the calling thread[.](#12.sentence-1)
[13](#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.4Timing specifications")) specified by rel_time expired,
otherwise cv_status::no_timeout[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10252)
*Throws*: Timeout-related
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#14.sentence-1)
[15](#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.2The std::terminate function"))[.](#15.sentence-1)
[*Note [3](#note-3)*:
This can happen if the re-locking of the mutex throws an exception[.](#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](#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](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10283)
[*Note [4](#note-4)*:
There is no blocking if pred() is initially true, or
if the timeout has already expired[.](#17.sentence-1)
— *end note*]
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10289)
[*Note [5](#note-5)*:
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered[.](#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](#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));

517
cppdraft/thread/coord.md Normal file
View File

@@ -0,0 +1,517 @@
[thread.coord]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [thread.coord]
### [32.9.1](#general) General [[thread.coord.general]](thread.coord.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10668)
Subclause [thread.coord] describes various concepts related to thread coordination, and
defines the coordination types latch and barrier[.](#general-1.sentence-1)
These types facilitate concurrent computation performed by a number of threads[.](#general-1.sentence-2)
### [32.9.2](#thread.latch) Latches [[thread.latch]](thread.latch)
#### [32.9.2.1](#thread.latch.general) General [[thread.latch.general]](thread.latch.general)
[1](#thread.latch.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10677)
A latch is a thread coordination mechanism
that allows any number of threads to block
until an expected number of threads arrive at the latch
(via the count_down function)[.](#thread.latch.general-1.sentence-1)
The expected count is set when the latch is created[.](#thread.latch.general-1.sentence-2)
An individual latch is a single-use object;
once the expected count has been reached, the latch cannot be reused[.](#thread.latch.general-1.sentence-3)
#### [32.9.2.2](#latch.syn) Header <latch> synopsis [[latch.syn]](latch.syn)
[🔗](#header:%3clatch%3e)
namespace std {class latch;}
#### [32.9.2.3](#thread.latch.class) Class latch [[thread.latch.class]](thread.latch.class)
namespace std {class latch {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit latch(ptrdiff_t expected); ~latch();
latch(const latch&) = delete;
latch& operator=(const latch&) = delete; void count_down(ptrdiff_t update = 1); bool try_wait() const noexcept; void wait() const; void arrive_and_wait(ptrdiff_t update = 1); private: ptrdiff_t counter; // *exposition only*};}
[1](#thread.latch.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10720)
A latch maintains an internal counter
that is initialized when the latch is created[.](#thread.latch.class-1.sentence-1)
Threads can block on the latch object,
waiting for counter to be decremented to zero[.](#thread.latch.class-1.sentence-2)
[2](#thread.latch.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10726)
Concurrent invocations of the member functions of latch,
other than its destructor, do not introduce data races[.](#thread.latch.class-2.sentence-1)
[🔗](#lib:max,latch)
`static constexpr ptrdiff_t max() noexcept;
`
[3](#thread.latch.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10736)
*Returns*: The maximum value of counter that the implementation supports[.](#thread.latch.class-3.sentence-1)
[🔗](#lib:latch,constructor)
`constexpr explicit latch(ptrdiff_t expected);
`
[4](#thread.latch.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10747)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#thread.latch.class-4.sentence-1)
[5](#thread.latch.class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10752)
*Effects*: Initializes counter with expected[.](#thread.latch.class-5.sentence-1)
[6](#thread.latch.class-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10756)
*Throws*: Nothing[.](#thread.latch.class-6.sentence-1)
[🔗](#lib:count_down,latch)
`void count_down(ptrdiff_t update = 1);
`
[7](#thread.latch.class-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10767)
*Preconditions*: update >= 0 is true, andupdate <= counter is true[.](#thread.latch.class-7.sentence-1)
[8](#thread.latch.class-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10772)
*Effects*: Atomically decrements counter by update[.](#thread.latch.class-8.sentence-1)
If counter is equal to zero,
unblocks all threads blocked on *this[.](#thread.latch.class-8.sentence-2)
[9](#thread.latch.class-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10778)
*Synchronization*: Strongly happens before the returns from all calls that are unblocked[.](#thread.latch.class-9.sentence-1)
[10](#thread.latch.class-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10782)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.latch.class-10.sentence-1)
[11](#thread.latch.class-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10786)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#thread.latch.class-11.sentence-1)
[🔗](#lib:try_wait,latch)
`bool try_wait() const noexcept;
`
[12](#thread.latch.class-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10798)
*Returns*: With very low probability false[.](#thread.latch.class-12.sentence-1)
Otherwise counter == 0[.](#thread.latch.class-12.sentence-2)
[🔗](#lib:wait,latch)
`void wait() const;
`
[13](#thread.latch.class-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10809)
*Effects*: If counter equals zero, returns immediately[.](#thread.latch.class-13.sentence-1)
Otherwise, blocks on *this until a call to count_down that decrements counter to zero[.](#thread.latch.class-13.sentence-2)
[14](#thread.latch.class-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10816)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.latch.class-14.sentence-1)
[15](#thread.latch.class-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10820)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#thread.latch.class-15.sentence-1)
[🔗](#lib:arrive_and_wait,latch)
`void arrive_and_wait(ptrdiff_t update = 1);
`
[16](#thread.latch.class-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10832)
*Effects*: Equivalent to:count_down(update);
wait();
### [32.9.3](#thread.barrier) Barriers [[thread.barrier]](thread.barrier)
#### [32.9.3.1](#thread.barrier.general) General [[thread.barrier.general]](thread.barrier.general)
[1](#thread.barrier.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10845)
A barrier is a thread coordination mechanism
whose lifetime consists of a sequence of barrier phases,
where each phase allows at most an expected number of threads to block
until the expected number of threads arrive at the barrier[.](#thread.barrier.general-1.sentence-1)
[*Note [1](#thread.barrier.general-note-1)*:
A barrier is useful for managing repeated tasks
that are handled by multiple threads[.](#thread.barrier.general-1.sentence-2)
— *end note*]
#### [32.9.3.2](#barrier.syn) Header <barrier> synopsis [[barrier.syn]](barrier.syn)
[🔗](#header:%3cbarrier%3e)
namespace std {template<class CompletionFunction = *see below*>class barrier;}
#### [32.9.3.3](#thread.barrier.class) Class template barrier [[thread.barrier.class]](thread.barrier.class)
namespace std {template<class CompletionFunction = *see below*>class barrier {public:using arrival_token = *see below*; static constexpr ptrdiff_t max() noexcept; constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction()); ~barrier();
barrier(const barrier&) = delete;
barrier& operator=(const barrier&) = delete;
arrival_token arrive(ptrdiff_t update = 1); void wait(arrival_token&& arrival) const; void arrive_and_wait(); void arrive_and_drop(); private: CompletionFunction completion; // *exposition only*};}
[1](#thread.barrier.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10895)
Each [*barrier phase*](#def:barrier_phase "32.9.3.3Class template barrier[thread.barrier.class]") consists of the following steps:
- [(1.1)](#thread.barrier.class-1.1)
The expected count is decremented
by each call to arrive or arrive_and_drop[.](#thread.barrier.class-1.1.sentence-1)
- [(1.2)](#thread.barrier.class-1.2)
Exactly once after the expected count reaches zero, a thread
executes the completion step during its call
to arrive, arrive_and_drop, or wait,
except that it is implementation-defined
whether the step executes if no thread calls wait[.](#thread.barrier.class-1.2.sentence-1)
- [(1.3)](#thread.barrier.class-1.3)
When the completion step finishes,
the expected count is reset
to what was specified by the expected argument to the constructor,
possibly adjusted by calls to arrive_and_drop, and
the next phase starts[.](#thread.barrier.class-1.3.sentence-1)
[2](#thread.barrier.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10916)
Each phase defines a [*phase synchronization point*](#def:barrier,phase_synchronization_point "32.9.3.3Class template barrier[thread.barrier.class]")[.](#thread.barrier.class-2.sentence-1)
Threads that arrive at the barrier during the phase
can block on the phase synchronization point by calling wait, and
will remain blocked until the phase completion step is run[.](#thread.barrier.class-2.sentence-2)
[3](#thread.barrier.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10923)
The [*phase completion step*](#def:phase_completion_step "32.9.3.3Class template barrier[thread.barrier.class]") that is executed at the end of each phase has the following effects:
- [(3.1)](#thread.barrier.class-3.1)
Invokes the completion function, equivalent to completion()[.](#thread.barrier.class-3.1.sentence-1)
- [(3.2)](#thread.barrier.class-3.2)
Unblocks all threads that are blocked on the phase synchronization point[.](#thread.barrier.class-3.2.sentence-1)
The end of the completion step strongly happens before
the returns from all calls that were unblocked by the completion step[.](#thread.barrier.class-3.sentence-2)
For specializations that do not have
the default value of the CompletionFunction template parameter,
the behavior is undefined if any of the barrier object's member functions
other than wait are called while the completion step is in progress[.](#thread.barrier.class-3.sentence-3)
[4](#thread.barrier.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10937)
Concurrent invocations of the member functions of barrier,
other than its destructor, do not introduce data races[.](#thread.barrier.class-4.sentence-1)
The member functions arrive and arrive_and_drop execute atomically[.](#thread.barrier.class-4.sentence-2)
[5](#thread.barrier.class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10943)
CompletionFunction shall meet the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")) and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#thread.barrier.class-5.sentence-1)
is_nothrow_invocable_v<CompletionFunction&> shall be true[.](#thread.barrier.class-5.sentence-2)
[6](#thread.barrier.class-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10949)
The default value of the CompletionFunction template parameter is
an unspecified type, such that,
in addition to satisfying the requirements of CompletionFunction,
it meets the [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") requirements (Table [30](utility.arg.requirements#tab:cpp17.defaultconstructible "Table 30: Cpp17DefaultConstructible requirements")) andcompletion() has no effects[.](#thread.barrier.class-6.sentence-1)
[7](#thread.barrier.class-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10957)
barrier::arrival_token is an unspecified type,
such that it meets the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements")),[*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [33](utility.arg.requirements#tab:cpp17.moveassignable "Table 33: Cpp17MoveAssignable requirements")), and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")) requirements[.](#thread.barrier.class-7.sentence-1)
[🔗](#lib:max,barrier)
`static constexpr ptrdiff_t max() noexcept;
`
[8](#thread.barrier.class-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10970)
*Returns*: The maximum expected count that the implementation supports[.](#thread.barrier.class-8.sentence-1)
[🔗](#lib:barrier,constructor)
`constexpr explicit barrier(ptrdiff_t expected,
CompletionFunction f = CompletionFunction());
`
[9](#thread.barrier.class-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10982)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#thread.barrier.class-9.sentence-1)
[10](#thread.barrier.class-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10987)
*Effects*: Sets both the initial expected count for each barrier phase and
the current expected count for the first phase to expected[.](#thread.barrier.class-10.sentence-1)
Initializes completion with std::move(f)[.](#thread.barrier.class-10.sentence-2)
Starts the first phase[.](#thread.barrier.class-10.sentence-3)
[*Note [1](#thread.barrier.class-note-1)*:
If expected is 0 this object can only be destroyed[.](#thread.barrier.class-10.sentence-4)
— *end note*]
[11](#thread.barrier.class-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10997)
*Throws*: Any exception thrown by CompletionFunction's move constructor[.](#thread.barrier.class-11.sentence-1)
[🔗](#lib:arrive,barrier)
`arrival_token arrive(ptrdiff_t update = 1);
`
[12](#thread.barrier.class-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11008)
*Preconditions*: update > 0 is true, andupdate is less than or equal to
the expected count for the current barrier phase[.](#thread.barrier.class-12.sentence-1)
[13](#thread.barrier.class-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11014)
*Effects*: Constructs an object of type arrival_token that is associated with the phase synchronization point for the current phase[.](#thread.barrier.class-13.sentence-1)
Then, decrements the expected count by update[.](#thread.barrier.class-13.sentence-2)
[14](#thread.barrier.class-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11020)
*Synchronization*: The call to arrive strongly happens before
the start of the phase completion step for the current phase[.](#thread.barrier.class-14.sentence-1)
[15](#thread.barrier.class-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11025)
*Returns*: The constructed arrival_token object[.](#thread.barrier.class-15.sentence-1)
[16](#thread.barrier.class-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11029)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.barrier.class-16.sentence-1)
[17](#thread.barrier.class-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11033)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#thread.barrier.class-17.sentence-1)
[18](#thread.barrier.class-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11038)
[*Note [2](#thread.barrier.class-note-2)*:
This call can cause the completion step for the current phase to start[.](#thread.barrier.class-18.sentence-1)
— *end note*]
[🔗](#lib:wait,barrier)
`void wait(arrival_token&& arrival) const;
`
[19](#thread.barrier.class-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11050)
*Preconditions*: arrival is associated with
the phase synchronization point for the current phase or
the immediately preceding phase of the same barrier object[.](#thread.barrier.class-19.sentence-1)
[20](#thread.barrier.class-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11056)
*Effects*: Blocks at the synchronization point associated with std::move(arrival) until the phase completion step of the synchronization point's phase is run[.](#thread.barrier.class-20.sentence-1)
[*Note [3](#thread.barrier.class-note-3)*:
If arrival is associated with the synchronization point
for a previous phase, the call returns immediately[.](#thread.barrier.class-20.sentence-2)
— *end note*]
[21](#thread.barrier.class-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11066)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.barrier.class-21.sentence-1)
[22](#thread.barrier.class-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11070)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#thread.barrier.class-22.sentence-1)
[🔗](#lib:arrive_and_wait,barrier)
`void arrive_and_wait();
`
[23](#thread.barrier.class-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11082)
*Effects*: Equivalent to: wait(arrive())[.](#thread.barrier.class-23.sentence-1)
[🔗](#lib:arrive_and_drop,barrier)
`void arrive_and_drop();
`
[24](#thread.barrier.class-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11093)
*Preconditions*: The expected count for the current barrier phase is greater than zero[.](#thread.barrier.class-24.sentence-1)
[25](#thread.barrier.class-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11097)
*Effects*: Decrements the initial expected count for all subsequent phases by one[.](#thread.barrier.class-25.sentence-1)
Then decrements the expected count for the current phase by one[.](#thread.barrier.class-25.sentence-2)
[26](#thread.barrier.class-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11102)
*Synchronization*: The call to arrive_and_drop strongly happens before
the start of the phase completion step for the current phase[.](#thread.barrier.class-26.sentence-1)
[27](#thread.barrier.class-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11107)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.barrier.class-27.sentence-1)
[28](#thread.barrier.class-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11111)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#thread.barrier.class-28.sentence-1)
[29](#thread.barrier.class-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11116)
[*Note [4](#thread.barrier.class-note-4)*:
This call can cause the completion step for the current phase to start[.](#thread.barrier.class-29.sentence-1)
— *end note*]

View File

@@ -0,0 +1,16 @@
[thread.coord.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#general)
### 32.9.1 General [thread.coord.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10668)
Subclause [[thread.coord]](thread.coord "32.9Coordination types") describes various concepts related to thread coordination, and
defines the coordination types latch and barrier[.](#1.sentence-1)
These types facilitate concurrent computation performed by a number of threads[.](#1.sentence-2)

View File

@@ -0,0 +1,28 @@
[thread.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.1 General [thread.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6)
The following subclauses describe components to create and manage[threads](intro.multithread#def:thread "6.10.2Multi-threaded executions and data races[intro.multithread]"), perform mutual exclusion, and communicate conditions
and values
between threads, as summarized in Table [154](#tab:thread.summary "Table 154: Concurrency support library summary")[.](#1.sentence-1)
Table [154](#tab:thread.summary) — Concurrency support library summary [[tab:thread.summary]](./tab:thread.summary)
| [🔗](#tab:thread.summary-row-1) | **Subclause** | **Header** |
| --- | --- | --- |
| [🔗](#tab:thread.summary-row-2)<br>[[thread.req]](thread.req "32.2Requirements") | Requirements | |
| [🔗](#tab:thread.summary-row-3)<br>[[thread.stoptoken]](thread.stoptoken "32.3Stop tokens") | Stop tokens | <stop_token> |
| [🔗](#tab:thread.summary-row-4)<br>[[thread.threads]](thread.threads "32.4Threads") | Threads | <thread> |
| [🔗](#tab:thread.summary-row-5)<br>[[atomics]](atomics "32.5Atomic operations") | Atomic operations | <atomic>, <stdatomic.h> |
| [🔗](#tab:thread.summary-row-6)<br>[[thread.mutex]](thread.mutex "32.6Mutual exclusion") | Mutual exclusion | <mutex>, <shared_mutex> |
| [🔗](#tab:thread.summary-row-7)<br>[[thread.condition]](thread.condition "32.7Condition variables") | Condition variables | <condition_variable> |
| [🔗](#tab:thread.summary-row-8)<br>[[thread.sema]](thread.sema "32.8Semaphore") | Semaphores | <semaphore> |
| [🔗](#tab:thread.summary-row-9)<br>[[thread.coord]](thread.coord "32.9Coordination types") | Coordination types | <latch>, <barrier> |
| [🔗](#tab:thread.summary-row-10)<br>[[futures]](futures "32.10Futures") | Futures | <future> |
| [🔗](#tab:thread.summary-row-11)<br>[[saferecl]](saferecl "32.11Safe reclamation") | Safe reclamation | <rcu>, <hazard_pointer> |

View File

@@ -0,0 +1,400 @@
[thread.jthread.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.class)
### 32.4.4 Class jthread [thread.jthread.class]
#### [32.4.4.1](#general) General [[thread.jthread.class.general]](thread.jthread.class.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1924)
The class jthread provides a mechanism
to create a new thread of execution[.](#general-1.sentence-1)
The functionality is the same as for
class thread ([[thread.thread.class]](thread.thread.class "32.4.3Class thread"))
with the additional abilities to provide
a stop_token ([[thread.stoptoken]](thread.stoptoken "32.3Stop tokens")) to the new thread of execution,
make stop requests, and automatically join[.](#general-1.sentence-2)
[🔗](#lib:jthread)
namespace std {class jthread {public:// typesusing id = thread::id; using native_handle_type = thread::native_handle_type; // [[thread.jthread.cons]](#thread.jthread.cons "32.4.4.2Constructors, move, and assignment"), constructors, move, and assignment jthread() noexcept; template<class F, class... Args> explicit jthread(F&& f, Args&&... args); ~jthread();
jthread(const jthread&) = delete;
jthread(jthread&&) noexcept;
jthread& operator=(const jthread&) = delete;
jthread& operator=(jthread&&) noexcept; // [[thread.jthread.mem]](#thread.jthread.mem "32.4.4.3Members"), membersvoid swap(jthread&) noexcept; bool joinable() const noexcept; void join(); void detach();
id get_id() const noexcept;
native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// [[thread.jthread.stop]](#thread.jthread.stop "32.4.4.4Stop token handling"), stop token handling stop_source get_stop_source() noexcept;
stop_token get_stop_token() const noexcept; bool request_stop() noexcept; // [[thread.jthread.special]](#thread.jthread.special "32.4.4.5Specialized algorithms"), specialized algorithmsfriend void swap(jthread& lhs, jthread& rhs) noexcept; // [[thread.jthread.static]](#thread.jthread.static "32.4.4.6Static members"), static membersstatic unsigned int hardware_concurrency() noexcept; private: stop_source ssource; // *exposition only*};}
#### [32.4.4.2](#thread.jthread.cons) Constructors, move, and assignment [[thread.jthread.cons]](thread.jthread.cons)
[🔗](#lib:jthread,constructor)
`jthread() noexcept;
`
[1](#thread.jthread.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1984)
*Effects*: Constructs a jthread object that does not represent
a thread of execution[.](#thread.jthread.cons-1.sentence-1)
[2](#thread.jthread.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1989)
*Postconditions*: get_id() == id() is true and ssource.stop_possible() is false[.](#thread.jthread.cons-2.sentence-1)
[🔗](#lib:jthread,constructor_)
`template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
`
[3](#thread.jthread.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2001)
*Constraints*: remove_cvref_t<F> is not the same type as jthread[.](#thread.jthread.cons-3.sentence-1)
[4](#thread.jthread.cons-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2005)
*Mandates*: The following are all true:
- [(4.1)](#thread.jthread.cons-4.1)
is_constructible_v<decay_t<F>, F>,
- [(4.2)](#thread.jthread.cons-4.2)
(is_constructible_v<decay_t<Args>, Args> && ...), and
- [(4.3)](#thread.jthread.cons-4.3)
is_invocable_v<decay_t<F>, decay_t<Args>...> ||
is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>[.](#thread.jthread.cons-4.3.sentence-2)
[5](#thread.jthread.cons-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2014)
*Effects*: Initializes ssource[.](#thread.jthread.cons-5.sentence-1)
The new thread of execution executesinvoke(auto(std::forward<F>(f)), get_stop_token(), // for invoke, see [[func.invoke]](func.invoke "22.10.5invoke functions")auto(std::forward<Args>(args))...) if that expression is well-formed,
otherwiseinvoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion")) in the constructing thread[.](#thread.jthread.cons-5.sentence-2)
Any return value from this invocation is ignored[.](#thread.jthread.cons-5.sentence-3)
[*Note [1](#thread.jthread.cons-note-1)*:
This implies that any exceptions not thrown from the invocation of the copy
of f will be thrown in the constructing thread, not the new thread[.](#thread.jthread.cons-5.sentence-4)
— *end note*]
If the invoke expression exits via an exception,terminate is called[.](#thread.jthread.cons-5.sentence-5)
[6](#thread.jthread.cons-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2037)
*Synchronization*: The completion of the invocation of the constructor
synchronizes with the beginning of the invocation of the copy of f[.](#thread.jthread.cons-6.sentence-1)
[7](#thread.jthread.cons-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2042)
*Postconditions*: get_id() != id() is true and ssource.stop_possible() is true and *this represents the newly started thread[.](#thread.jthread.cons-7.sentence-1)
[*Note [2](#thread.jthread.cons-note-2)*:
The calling thread can make a stop request only once,
because it cannot replace this stop token[.](#thread.jthread.cons-7.sentence-2)
— *end note*]
[8](#thread.jthread.cons-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2052)
*Throws*: system_error if unable to start the new thread[.](#thread.jthread.cons-8.sentence-1)
[9](#thread.jthread.cons-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2056)
*Error conditions*:
- [(9.1)](#thread.jthread.cons-9.1)
resource_unavailable_try_again — the system lacked
the necessary resources to create another thread,
or the system-imposed limit on the number of threads in a process
would be exceeded[.](#thread.jthread.cons-9.sentence-1)
[🔗](#lib:jthread,constructor__)
`jthread(jthread&& x) noexcept;
`
[10](#thread.jthread.cons-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2072)
*Postconditions*: x.get_id() == id() and get_id() returns the value of x.get_id() prior to the start of construction[.](#thread.jthread.cons-10.sentence-1)
ssource has the value of x.ssource prior to the start of construction
and x.ssource.stop_possible() is false[.](#thread.jthread.cons-10.sentence-2)
[🔗](#lib:jthread,destructor)
`~jthread();
`
[11](#thread.jthread.cons-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2088)
*Effects*: If joinable() is true,
calls request_stop() and then join()[.](#thread.jthread.cons-11.sentence-1)
[*Note [3](#thread.jthread.cons-note-3)*:
Operations on *this are not synchronized[.](#thread.jthread.cons-11.sentence-2)
— *end note*]
[🔗](#lib:operator=,jthread)
`jthread& operator=(jthread&& x) noexcept;
`
[12](#thread.jthread.cons-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2103)
*Effects*: If &x == this is true, there are no effects[.](#thread.jthread.cons-12.sentence-1)
Otherwise, if joinable() is true,
calls request_stop() and then join(),
then assigns the state of x to *this and sets x to a default constructed state[.](#thread.jthread.cons-12.sentence-2)
[13](#thread.jthread.cons-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2111)
*Postconditions*: get_id() returns the value of x.get_id() prior to the assignment[.](#thread.jthread.cons-13.sentence-1)
ssource has the value of x.ssource prior to the assignment[.](#thread.jthread.cons-13.sentence-2)
[14](#thread.jthread.cons-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2118)
*Returns*: *this[.](#thread.jthread.cons-14.sentence-1)
#### [32.4.4.3](#thread.jthread.mem) Members [[thread.jthread.mem]](thread.jthread.mem)
[🔗](#lib:swap,jthread)
`void swap(jthread& x) noexcept;
`
[1](#thread.jthread.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2131)
*Effects*: Exchanges the values of *this and x[.](#thread.jthread.mem-1.sentence-1)
[🔗](#lib:joinable,jthread)
`bool joinable() const noexcept;
`
[2](#thread.jthread.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2142)
*Returns*: get_id() != id()[.](#thread.jthread.mem-2.sentence-1)
[🔗](#lib:join,jthread)
`void join();
`
[3](#thread.jthread.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2153)
*Effects*: Blocks until the thread represented by *this has completed[.](#thread.jthread.mem-3.sentence-1)
[4](#thread.jthread.mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2158)
*Synchronization*: The completion of the thread represented by *this synchronizes with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
the corresponding successful join() return[.](#thread.jthread.mem-4.sentence-1)
[*Note [1](#thread.jthread.mem-note-1)*:
Operations on *this are not synchronized[.](#thread.jthread.mem-4.sentence-2)
— *end note*]
[5](#thread.jthread.mem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2167)
*Postconditions*: The thread represented by *this has completed[.](#thread.jthread.mem-5.sentence-1)
get_id() == id()[.](#thread.jthread.mem-5.sentence-2)
[6](#thread.jthread.mem-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2172)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.jthread.mem-6.sentence-1)
[7](#thread.jthread.mem-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2176)
*Error conditions*:
- [(7.1)](#thread.jthread.mem-7.1)
resource_deadlock_would_occur — if deadlock is detected orget_id() == this_thread::get_id()[.](#thread.jthread.mem-7.1.sentence-1)
- [(7.2)](#thread.jthread.mem-7.2)
no_such_process — if the thread is not valid[.](#thread.jthread.mem-7.2.sentence-1)
- [(7.3)](#thread.jthread.mem-7.3)
invalid_argument — if the thread is not joinable[.](#thread.jthread.mem-7.3.sentence-1)
[🔗](#lib:detach,jthread)
`void detach();
`
[8](#thread.jthread.mem-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2194)
*Effects*: The thread represented by *this continues execution
without the calling thread blocking[.](#thread.jthread.mem-8.sentence-1)
When detach() returns,*this no longer represents the possibly continuing thread of execution[.](#thread.jthread.mem-8.sentence-2)
When the thread previously represented by *this ends execution,
the implementation releases any owned resources[.](#thread.jthread.mem-8.sentence-3)
[9](#thread.jthread.mem-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2203)
*Postconditions*: get_id() == id()[.](#thread.jthread.mem-9.sentence-1)
[10](#thread.jthread.mem-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2207)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.jthread.mem-10.sentence-1)
[11](#thread.jthread.mem-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2211)
*Error conditions*:
- [(11.1)](#thread.jthread.mem-11.1)
no_such_process — if the thread is not valid[.](#thread.jthread.mem-11.1.sentence-1)
- [(11.2)](#thread.jthread.mem-11.2)
invalid_argument — if the thread is not joinable[.](#thread.jthread.mem-11.2.sentence-1)
[🔗](#lib:get_id,jthread)
`id get_id() const noexcept;
`
[12](#thread.jthread.mem-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2225)
*Returns*: A default constructed id object
if *this does not represent a thread,
otherwise this_thread::get_id() for the thread of execution represented by *this[.](#thread.jthread.mem-12.sentence-1)
#### [32.4.4.4](#thread.jthread.stop) Stop token handling [[thread.jthread.stop]](thread.jthread.stop)
[🔗](#lib:get_stop_source,jthread)
`stop_source get_stop_source() noexcept;
`
[1](#thread.jthread.stop-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2241)
*Effects*: Equivalent to: return ssource;
[🔗](#lib:get_stop_token,jthread)
`stop_token get_stop_token() const noexcept;
`
[2](#thread.jthread.stop-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2252)
*Effects*: Equivalent to: return ssource.get_token();
[🔗](#lib:request_stop,jthread)
`bool request_stop() noexcept;
`
[3](#thread.jthread.stop-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2263)
*Effects*: Equivalent to: return ssource.request_stop();
#### [32.4.4.5](#thread.jthread.special) Specialized algorithms [[thread.jthread.special]](thread.jthread.special)
[🔗](#lib:swap,jthread_)
`friend void swap(jthread& x, jthread& y) noexcept;
`
[1](#thread.jthread.special-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2277)
*Effects*: Equivalent to: x.swap(y)[.](#thread.jthread.special-1.sentence-1)
#### [32.4.4.6](#thread.jthread.static) Static members [[thread.jthread.static]](thread.jthread.static)
[🔗](#lib:hardware_concurrency,jthread)
`static unsigned int hardware_concurrency() noexcept;
`
[1](#thread.jthread.static-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2290)
*Returns*: thread::hardware_concurrency()[.](#thread.jthread.static-1.sentence-1)

View File

@@ -0,0 +1,33 @@
[thread.jthread.class.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.class.general)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#general)
#### 32.4.4.1 General [thread.jthread.class.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1924)
The class jthread provides a mechanism
to create a new thread of execution[.](#1.sentence-1)
The functionality is the same as for
class thread ([[thread.thread.class]](thread.thread.class "32.4.3Class thread"))
with the additional abilities to provide
a stop_token ([[thread.stoptoken]](thread.stoptoken "32.3Stop tokens")) to the new thread of execution,
make stop requests, and automatically join[.](#1.sentence-2)
[🔗](#lib:jthread)
namespace std {class jthread {public:// typesusing id = thread::id; using native_handle_type = thread::native_handle_type; // [[thread.jthread.cons]](thread.jthread.cons "32.4.4.2Constructors, move, and assignment"), constructors, move, and assignment jthread() noexcept; template<class F, class... Args> explicit jthread(F&& f, Args&&... args); ~jthread();
jthread(const jthread&) = delete;
jthread(jthread&&) noexcept;
jthread& operator=(const jthread&) = delete;
jthread& operator=(jthread&&) noexcept; // [[thread.jthread.mem]](thread.jthread.mem "32.4.4.3Members"), membersvoid swap(jthread&) noexcept; bool joinable() const noexcept; void join(); void detach();
id get_id() const noexcept;
native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// [[thread.jthread.stop]](thread.jthread.stop "32.4.4.4Stop token handling"), stop token handling stop_source get_stop_source() noexcept;
stop_token get_stop_token() const noexcept; bool request_stop() noexcept; // [[thread.jthread.special]](thread.jthread.special "32.4.4.5Specialized algorithms"), specialized algorithmsfriend void swap(jthread& lhs, jthread& rhs) noexcept; // [[thread.jthread.static]](thread.jthread.static "32.4.4.6Static members"), static membersstatic unsigned int hardware_concurrency() noexcept; private: stop_source ssource; // *exposition only*};}

View File

@@ -0,0 +1,177 @@
[thread.jthread.cons]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.cons)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#thread.jthread.cons)
#### 32.4.4.2 Constructors, move, and assignment [thread.jthread.cons]
[🔗](#lib:jthread,constructor)
`jthread() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1984)
*Effects*: Constructs a jthread object that does not represent
a thread of execution[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1989)
*Postconditions*: get_id() == id() is true and ssource.stop_possible() is false[.](#2.sentence-1)
[🔗](#lib:jthread,constructor_)
`template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2001)
*Constraints*: remove_cvref_t<F> is not the same type as jthread[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2005)
*Mandates*: The following are all true:
- [(4.1)](#4.1)
is_constructible_v<decay_t<F>, F>,
- [(4.2)](#4.2)
(is_constructible_v<decay_t<Args>, Args> && ...), and
- [(4.3)](#4.3)
is_invocable_v<decay_t<F>, decay_t<Args>...> ||
is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>[.](#4.3.sentence-2)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2014)
*Effects*: Initializes ssource[.](#5.sentence-1)
The new thread of execution executesinvoke(auto(std::forward<F>(f)), get_stop_token(), // for invoke, see [[func.invoke]](func.invoke "22.10.5invoke functions")auto(std::forward<Args>(args))...) if that expression is well-formed,
otherwiseinvoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion")) in the constructing thread[.](#5.sentence-2)
Any return value from this invocation is ignored[.](#5.sentence-3)
[*Note [1](#note-1)*:
This implies that any exceptions not thrown from the invocation of the copy
of f will be thrown in the constructing thread, not the new thread[.](#5.sentence-4)
— *end note*]
If the invoke expression exits via an exception,terminate is called[.](#5.sentence-5)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2037)
*Synchronization*: The completion of the invocation of the constructor
synchronizes with the beginning of the invocation of the copy of f[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2042)
*Postconditions*: get_id() != id() is true and ssource.stop_possible() is true and *this represents the newly started thread[.](#7.sentence-1)
[*Note [2](#note-2)*:
The calling thread can make a stop request only once,
because it cannot replace this stop token[.](#7.sentence-2)
— *end note*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2052)
*Throws*: system_error if unable to start the new thread[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2056)
*Error conditions*:
- [(9.1)](#9.1)
resource_unavailable_try_again — the system lacked
the necessary resources to create another thread,
or the system-imposed limit on the number of threads in a process
would be exceeded[.](#9.sentence-1)
[🔗](#lib:jthread,constructor__)
`jthread(jthread&& x) noexcept;
`
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2072)
*Postconditions*: x.get_id() == id() and get_id() returns the value of x.get_id() prior to the start of construction[.](#10.sentence-1)
ssource has the value of x.ssource prior to the start of construction
and x.ssource.stop_possible() is false[.](#10.sentence-2)
[🔗](#lib:jthread,destructor)
`~jthread();
`
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2088)
*Effects*: If joinable() is true,
calls request_stop() and then join()[.](#11.sentence-1)
[*Note [3](#note-3)*:
Operations on *this are not synchronized[.](#11.sentence-2)
— *end note*]
[🔗](#lib:operator=,jthread)
`jthread& operator=(jthread&& x) noexcept;
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2103)
*Effects*: If &x == this is true, there are no effects[.](#12.sentence-1)
Otherwise, if joinable() is true,
calls request_stop() and then join(),
then assigns the state of x to *this and sets x to a default constructed state[.](#12.sentence-2)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2111)
*Postconditions*: get_id() returns the value of x.get_id() prior to the assignment[.](#13.sentence-1)
ssource has the value of x.ssource prior to the assignment[.](#13.sentence-2)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2118)
*Returns*: *this[.](#14.sentence-1)

View File

@@ -0,0 +1,143 @@
[thread.jthread.mem]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.mem)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#thread.jthread.mem)
#### 32.4.4.3 Members [thread.jthread.mem]
[🔗](#lib:swap,jthread)
`void swap(jthread& x) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2131)
*Effects*: Exchanges the values of *this and x[.](#1.sentence-1)
[🔗](#lib:joinable,jthread)
`bool joinable() const noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2142)
*Returns*: get_id() != id()[.](#2.sentence-1)
[🔗](#lib:join,jthread)
`void join();
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2153)
*Effects*: Blocks until the thread represented by *this has completed[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2158)
*Synchronization*: The completion of the thread represented by *this synchronizes with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
the corresponding successful join() return[.](#4.sentence-1)
[*Note [1](#note-1)*:
Operations on *this are not synchronized[.](#4.sentence-2)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2167)
*Postconditions*: The thread represented by *this has completed[.](#5.sentence-1)
get_id() == id()[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2172)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2176)
*Error conditions*:
- [(7.1)](#7.1)
resource_deadlock_would_occur — if deadlock is detected orget_id() == this_thread::get_id()[.](#7.1.sentence-1)
- [(7.2)](#7.2)
no_such_process — if the thread is not valid[.](#7.2.sentence-1)
- [(7.3)](#7.3)
invalid_argument — if the thread is not joinable[.](#7.3.sentence-1)
[🔗](#lib:detach,jthread)
`void detach();
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2194)
*Effects*: The thread represented by *this continues execution
without the calling thread blocking[.](#8.sentence-1)
When detach() returns,*this no longer represents the possibly continuing thread of execution[.](#8.sentence-2)
When the thread previously represented by *this ends execution,
the implementation releases any owned resources[.](#8.sentence-3)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2203)
*Postconditions*: get_id() == id()[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2207)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2211)
*Error conditions*:
- [(11.1)](#11.1)
no_such_process — if the thread is not valid[.](#11.1.sentence-1)
- [(11.2)](#11.2)
invalid_argument — if the thread is not joinable[.](#11.2.sentence-1)
[🔗](#lib:get_id,jthread)
`id get_id() const noexcept;
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2225)
*Returns*: A default constructed id object
if *this does not represent a thread,
otherwise this_thread::get_id() for the thread of execution represented by *this[.](#12.sentence-1)

View File

@@ -0,0 +1,20 @@
[thread.jthread.special]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.special)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#thread.jthread.special)
#### 32.4.4.5 Specialized algorithms [thread.jthread.special]
[🔗](#lib:swap,jthread)
`friend void swap(jthread& x, jthread& y) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2277)
*Effects*: Equivalent to: x.swap(y)[.](#1.sentence-1)

View File

@@ -0,0 +1,20 @@
[thread.jthread.static]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.static)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#thread.jthread.static)
#### 32.4.4.6 Static members [thread.jthread.static]
[🔗](#lib:hardware_concurrency,jthread)
`static unsigned int hardware_concurrency() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2290)
*Returns*: thread::hardware_concurrency()[.](#1.sentence-1)

View File

@@ -0,0 +1,42 @@
[thread.jthread.stop]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.jthread.stop)
### 32.4.4 Class jthread [[thread.jthread.class]](thread.jthread.class#thread.jthread.stop)
#### 32.4.4.4 Stop token handling [thread.jthread.stop]
[🔗](#lib:get_stop_source,jthread)
`stop_source get_stop_source() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2241)
*Effects*: Equivalent to: return ssource;
[🔗](#lib:get_stop_token,jthread)
`stop_token get_stop_token() const noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2252)
*Effects*: Equivalent to: return ssource.get_token();
[🔗](#lib:request_stop,jthread)
`bool request_stop() noexcept;
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2263)
*Effects*: Equivalent to: return ssource.request_stop();

177
cppdraft/thread/latch.md Normal file
View File

@@ -0,0 +1,177 @@
[thread.latch]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.latch)
### 32.9.2 Latches [thread.latch]
#### [32.9.2.1](#general) General [[thread.latch.general]](thread.latch.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10677)
A latch is a thread coordination mechanism
that allows any number of threads to block
until an expected number of threads arrive at the latch
(via the count_down function)[.](#general-1.sentence-1)
The expected count is set when the latch is created[.](#general-1.sentence-2)
An individual latch is a single-use object;
once the expected count has been reached, the latch cannot be reused[.](#general-1.sentence-3)
#### [32.9.2.2](#latch.syn) Header <latch> synopsis [[latch.syn]](latch.syn)
[🔗](#header:%3clatch%3e)
namespace std {class latch;}
#### [32.9.2.3](#class) Class latch [[thread.latch.class]](thread.latch.class)
namespace std {class latch {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit latch(ptrdiff_t expected); ~latch();
latch(const latch&) = delete;
latch& operator=(const latch&) = delete; void count_down(ptrdiff_t update = 1); bool try_wait() const noexcept; void wait() const; void arrive_and_wait(ptrdiff_t update = 1); private: ptrdiff_t counter; // *exposition only*};}
[1](#class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10720)
A latch maintains an internal counter
that is initialized when the latch is created[.](#class-1.sentence-1)
Threads can block on the latch object,
waiting for counter to be decremented to zero[.](#class-1.sentence-2)
[2](#class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10726)
Concurrent invocations of the member functions of latch,
other than its destructor, do not introduce data races[.](#class-2.sentence-1)
[🔗](#lib:max,latch)
`static constexpr ptrdiff_t max() noexcept;
`
[3](#class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10736)
*Returns*: The maximum value of counter that the implementation supports[.](#class-3.sentence-1)
[🔗](#lib:latch,constructor)
`constexpr explicit latch(ptrdiff_t expected);
`
[4](#class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10747)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#class-4.sentence-1)
[5](#class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10752)
*Effects*: Initializes counter with expected[.](#class-5.sentence-1)
[6](#class-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10756)
*Throws*: Nothing[.](#class-6.sentence-1)
[🔗](#lib:count_down,latch)
`void count_down(ptrdiff_t update = 1);
`
[7](#class-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10767)
*Preconditions*: update >= 0 is true, andupdate <= counter is true[.](#class-7.sentence-1)
[8](#class-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10772)
*Effects*: Atomically decrements counter by update[.](#class-8.sentence-1)
If counter is equal to zero,
unblocks all threads blocked on *this[.](#class-8.sentence-2)
[9](#class-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10778)
*Synchronization*: Strongly happens before the returns from all calls that are unblocked[.](#class-9.sentence-1)
[10](#class-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10782)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#class-10.sentence-1)
[11](#class-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10786)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#class-11.sentence-1)
[🔗](#lib:try_wait,latch)
`bool try_wait() const noexcept;
`
[12](#class-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10798)
*Returns*: With very low probability false[.](#class-12.sentence-1)
Otherwise counter == 0[.](#class-12.sentence-2)
[🔗](#lib:wait,latch)
`void wait() const;
`
[13](#class-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10809)
*Effects*: If counter equals zero, returns immediately[.](#class-13.sentence-1)
Otherwise, blocks on *this until a call to count_down that decrements counter to zero[.](#class-13.sentence-2)
[14](#class-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10816)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#class-14.sentence-1)
[15](#class-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10820)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#class-15.sentence-1)
[🔗](#lib:arrive_and_wait,latch)
`void arrive_and_wait(ptrdiff_t update = 1);
`
[16](#class-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10832)
*Effects*: Equivalent to:count_down(update);
wait();

View File

@@ -0,0 +1,155 @@
[thread.latch.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.latch.class)
### 32.9.2 Latches [[thread.latch]](thread.latch#class)
#### 32.9.2.3 Class latch [thread.latch.class]
namespace std {class latch {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit latch(ptrdiff_t expected); ~latch();
latch(const latch&) = delete;
latch& operator=(const latch&) = delete; void count_down(ptrdiff_t update = 1); bool try_wait() const noexcept; void wait() const; void arrive_and_wait(ptrdiff_t update = 1); private: ptrdiff_t counter; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10720)
A latch maintains an internal counter
that is initialized when the latch is created[.](#1.sentence-1)
Threads can block on the latch object,
waiting for counter to be decremented to zero[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10726)
Concurrent invocations of the member functions of latch,
other than its destructor, do not introduce data races[.](#2.sentence-1)
[🔗](#lib:max,latch)
`static constexpr ptrdiff_t max() noexcept;
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10736)
*Returns*: The maximum value of counter that the implementation supports[.](#3.sentence-1)
[🔗](#lib:latch,constructor)
`constexpr explicit latch(ptrdiff_t expected);
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10747)
*Preconditions*: expected >= 0 is true andexpected <= max() is true[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10752)
*Effects*: Initializes counter with expected[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10756)
*Throws*: Nothing[.](#6.sentence-1)
[🔗](#lib:count_down,latch)
`void count_down(ptrdiff_t update = 1);
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10767)
*Preconditions*: update >= 0 is true, andupdate <= counter is true[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10772)
*Effects*: Atomically decrements counter by update[.](#8.sentence-1)
If counter is equal to zero,
unblocks all threads blocked on *this[.](#8.sentence-2)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10778)
*Synchronization*: Strongly happens before the returns from all calls that are unblocked[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10782)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10786)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#11.sentence-1)
[🔗](#lib:try_wait,latch)
`bool try_wait() const noexcept;
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10798)
*Returns*: With very low probability false[.](#12.sentence-1)
Otherwise counter == 0[.](#12.sentence-2)
[🔗](#lib:wait,latch)
`void wait() const;
`
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10809)
*Effects*: If counter equals zero, returns immediately[.](#13.sentence-1)
Otherwise, blocks on *this until a call to count_down that decrements counter to zero[.](#13.sentence-2)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10816)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10820)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#15.sentence-1)
[🔗](#lib:arrive_and_wait,latch)
`void arrive_and_wait(ptrdiff_t update = 1);
`
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10832)
*Effects*: Equivalent to:count_down(update);
wait();

View File

@@ -0,0 +1,23 @@
[thread.latch.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.9 Coordination types [[thread.coord]](thread.coord#thread.latch.general)
### 32.9.2 Latches [[thread.latch]](thread.latch#general)
#### 32.9.2.1 General [thread.latch.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10677)
A latch is a thread coordination mechanism
that allows any number of threads to block
until an expected number of threads arrive at the latch
(via the count_down function)[.](#1.sentence-1)
The expected count is set when the latch is created[.](#1.sentence-2)
An individual latch is a single-use object;
once the expected count has been reached, the latch cannot be reused[.](#1.sentence-3)

1258
cppdraft/thread/lock.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
[thread.lock.algorithm]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.algorithm)
### 32.6.6 Generic locking algorithms [thread.lock.algorithm]
[🔗](#lib:try_lock)
`template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9310)
*Preconditions*: Each template parameter type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements[.](#1.sentence-1)
[*Note [1](#note-1)*:
Theunique_lock class template meets these requirements when suitably instantiated[.](#1.sentence-2)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9318)
*Effects*: Calls try_lock() for each argument in order beginning with the
first until all arguments have been processed or a call to try_lock() fails,
either by returning false or by throwing an exception[.](#2.sentence-1)
If a call totry_lock() fails, unlock() is called for all prior arguments
with no further calls to try_lock()[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9326)
*Returns*: -1 if all calls to try_lock() returned true,
otherwise a zero-based index value that indicates the argument for which try_lock() returned false[.](#3.sentence-1)
[🔗](#lib:lock)
`template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9339)
*Preconditions*: Each template parameter type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements[.](#4.sentence-1)
[*Note [2](#note-2)*:
Theunique_lock class template meets these requirements when suitably instantiated[.](#4.sentence-2)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9347)
*Effects*: All arguments are locked via a sequence of calls to lock(),try_lock(), or unlock() on each argument[.](#5.sentence-1)
The sequence of calls does
not result in deadlock, but is otherwise unspecified[.](#5.sentence-2)
[*Note [3](#note-3)*:
A deadlock avoidance
algorithm such as try-and-back-off can be used, but the specific algorithm is not
specified to avoid over-constraining implementations[.](#5.sentence-3)
— *end note*]
If a call tolock() or try_lock() throws an exception, unlock() is
called for any argument that had been locked by a call to lock() ortry_lock()[.](#5.sentence-4)

View File

@@ -0,0 +1,44 @@
[thread.lock.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.general)
### 32.6.5 Locks [[thread.lock]](thread.lock#general)
#### 32.6.5.1 General [thread.lock.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8144)
A [*lock*](#def:lock) is an object that holds a reference to a lockable object and may unlock the
lockable object during the lock's destruction (such as when leaving block scope)[.](#1.sentence-1)
An execution
agent may use a lock to aid in managing ownership of a lockable object in an exception safe
manner[.](#1.sentence-2)
A lock is said to [*own*](#def:own) a lockable object if it is currently managing the
ownership of that lockable object for an execution agent[.](#1.sentence-3)
A lock does not manage the lifetime
of the lockable object it references[.](#1.sentence-4)
[*Note [1](#note-1)*:
Locks are intended to ease the burden of
unlocking the lockable object under both normal and exceptional circumstances[.](#1.sentence-5)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8156)
Some lock constructors take tag types which describe what should be done with the lockable
object during the lock's construction[.](#2.sentence-1)
[🔗](#lib:defer_lock_t)
namespace std {struct defer_lock_t { }; // do not acquire ownership of the mutexstruct try_to_lock_t { }; // try to acquire ownership of the mutex// without blockingstruct adopt_lock_t { }; // assume the calling thread has already// obtained mutex ownership and manage itinline constexpr defer_lock_t defer_lock { }; inline constexpr try_to_lock_t try_to_lock { }; inline constexpr adopt_lock_t adopt_lock { };}

View File

@@ -0,0 +1,78 @@
[thread.lock.guard]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.guard)
### 32.6.5 Locks [[thread.lock]](thread.lock#guard)
#### 32.6.5.2 Class template lock_guard [thread.lock.guard]
[🔗](#lib:lock_guard)
namespace std {template<class Mutex>class lock_guard {public:using mutex_type = Mutex; explicit lock_guard(mutex_type& m);
lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard();
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete; private: mutex_type& pm; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8203)
An object of type lock_guard controls the ownership of a lockable object
within a scope[.](#1.sentence-1)
A lock_guard object maintains ownership of a lockable
object throughout the lock_guard object's [lifetime](basic.life#def:lifetime "6.8.4Lifetime[basic.life]")[.](#1.sentence-2)
The behavior of a program is undefined if the lockable object referenced bypm does not exist for the entire lifetime of the lock_guard object[.](#1.sentence-3)
The supplied Mutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#1.sentence-4)
[🔗](#lib:lock_guard,constructor)
`explicit lock_guard(mutex_type& m);
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8218)
*Effects*: Initializes pm with m[.](#2.sentence-1)
Calls m.lock()[.](#2.sentence-2)
[🔗](#lib:lock_guard,constructor_)
`lock_guard(mutex_type& m, adopt_lock_t);
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8229)
*Preconditions*: The calling thread holds a non-shared lock on m[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8233)
*Effects*: Initializes pm with m[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8237)
*Throws*: Nothing[.](#5.sentence-1)
[🔗](#lib:lock_guard,destructor)
`~lock_guard();
`
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8248)
*Effects*: Equivalent to: pm.unlock()

View File

@@ -0,0 +1,91 @@
[thread.lock.scoped]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.scoped)
### 32.6.5 Locks [[thread.lock]](thread.lock#scoped)
#### 32.6.5.3 Class template scoped_lock [thread.lock.scoped]
[🔗](#lib:scoped_lock)
namespace std {template<class... MutexTypes>class scoped_lock {public:using mutex_type = *see below*; // Only if sizeof...(MutexTypes) == 1 is trueexplicit scoped_lock(MutexTypes&... m); explicit scoped_lock(adopt_lock_t, MutexTypes&... m); ~scoped_lock();
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete; private: tuple<MutexTypes&...> pm; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8276)
An object of type scoped_lock controls the ownership of lockable objects
within a scope[.](#1.sentence-1)
A scoped_lock object maintains ownership of lockable
objects throughout the scoped_lock object's [lifetime](basic.life#def:lifetime "6.8.4Lifetime[basic.life]")[.](#1.sentence-2)
The behavior of a program is undefined if the lockable objects referenced bypm do not exist for the entire lifetime of the scoped_lock object[.](#1.sentence-3)
- [(1.1)](#1.1)
If sizeof...(MutexTypes) is one,
let Mutex denote the sole type constituting the pack MutexTypes[.](#1.1.sentence-1)
Mutex shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#1.1.sentence-2)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") mutex_type denotes the same type as Mutex[.](#1.1.sentence-3)
- [(1.2)](#1.2)
Otherwise, all types in the template parameter pack MutexTypes shall meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))
and there is no member mutex_type[.](#1.2.sentence-1)
[🔗](#lib:scoped_lock,constructor)
`explicit scoped_lock(MutexTypes&... m);
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8303)
*Effects*: Initializes pm with tie(m...)[.](#2.sentence-1)
Then if sizeof...(MutexTypes) is 0, no effects[.](#2.sentence-2)
Otherwise if sizeof...(MutexTypes) is 1, then m.lock()[.](#2.sentence-3)
Otherwise, lock(m...)[.](#2.sentence-4)
[🔗](#lib:scoped_lock,constructor_)
`explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8317)
*Preconditions*: The calling thread holds a non-shared lock on each element of m[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8321)
*Effects*: Initializes pm with tie(m...)[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8325)
*Throws*: Nothing[.](#5.sentence-1)
[🔗](#lib:scoped_lock,destructor)
`~scoped_lock();
`
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8336)
*Effects*: For all i in [0, sizeof...(MutexTypes)),get<i>(pm).unlock()[.](#6.sentence-1)

View File

@@ -0,0 +1,525 @@
[thread.lock.shared]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared)
#### 32.6.5.5 Class template shared_lock [thread.lock.shared]
#### [32.6.5.5.1](#general) General [[thread.lock.shared.general]](thread.lock.shared.general)
[🔗](#lib:shared_lock)
namespace std {template<class Mutex>class shared_lock {public:using mutex_type = Mutex; // [[thread.lock.shared.cons]](#cons "32.6.5.5.2Constructors, destructor, and assignment"), construct/copy/destroy shared_lock() noexcept; explicit shared_lock(mutex_type& m); // blocking shared_lock(mutex_type& m, defer_lock_t) noexcept;
shared_lock(mutex_type& m, try_to_lock_t);
shared_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~shared_lock();
shared_lock(const shared_lock&) = delete;
shared_lock& operator=(const shared_lock&) = delete;
shared_lock(shared_lock&& u) noexcept;
shared_lock& operator=(shared_lock&& u) noexcept; // [[thread.lock.shared.locking]](#locking "32.6.5.5.3Locking"), lockingvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.shared.mod]](#mod "32.6.5.5.4Modifiers"), modifiersvoid swap(shared_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.shared.obs]](#obs "32.6.5.5.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8881)
An object of type shared_lock controls the shared ownership of a
lockable object within a scope[.](#general-1.sentence-1)
Shared ownership of the lockable object may be
acquired at construction or after construction, and may be transferred, after
acquisition, to another shared_lock object[.](#general-1.sentence-2)
Objects of typeshared_lock are not copyable but are movable[.](#general-1.sentence-3)
The behavior of a program
is undefined if the contained pointer pm is not null and the lockable
object pointed to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the shared_lock object[.](#general-1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#general-1.sentence-5)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8893)
[*Note [1](#general-note-1)*:
shared_lock<Mutex> meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#general-2.sentence-1)
If Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements")),shared_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#general-2.sentence-2)
— *end note*]
#### [32.6.5.5.2](#cons) Constructors, destructor, and assignment [[thread.lock.shared.cons]](thread.lock.shared.cons)
[🔗](#lib:shared_lock,constructor)
`shared_lock() noexcept;
`
[1](#cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8911)
*Postconditions*: pm == nullptr and owns == false[.](#cons-1.sentence-1)
[🔗](#lib:shared_lock,constructor_)
`explicit shared_lock(mutex_type& m);
`
[2](#cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8922)
*Effects*: Calls m.lock_shared()[.](#cons-2.sentence-1)
[3](#cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8926)
*Postconditions*: pm == addressof(m) and owns == true[.](#cons-3.sentence-1)
[🔗](#lib:shared_lock,constructor__)
`shared_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#cons-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8937)
*Postconditions*: pm == addressof(m) and owns == false[.](#cons-4.sentence-1)
[🔗](#lib:shared_lock,constructor___)
`shared_lock(mutex_type& m, try_to_lock_t);
`
[5](#cons-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8948)
*Effects*: Calls m.try_lock_shared()[.](#cons-5.sentence-1)
[6](#cons-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8952)
*Postconditions*: pm == addressof(m) and owns == res where res is the
value returned by the call to m.try_lock_shared()[.](#cons-6.sentence-1)
[🔗](#lib:shared_lock,constructor____)
`shared_lock(mutex_type& m, adopt_lock_t);
`
[7](#cons-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8965)
*Preconditions*: The calling thread holds a shared lock on m[.](#cons-7.sentence-1)
[8](#cons-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8969)
*Postconditions*: pm == addressof(m) and owns == true[.](#cons-8.sentence-1)
[🔗](#lib:shared_lock,constructor_____)
`template<class Clock, class Duration>
shared_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& abs_time);
`
[9](#cons-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8982)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#cons-9.sentence-1)
[10](#cons-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8987)
*Effects*: Calls m.try_lock_shared_until(abs_time)[.](#cons-10.sentence-1)
[11](#cons-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8991)
*Postconditions*: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_lock_shared_until(abs_time)[.](#cons-11.sentence-1)
[🔗](#lib:shared_lock,constructor______)
`template<class Rep, class Period>
shared_lock(mutex_type& m,
const chrono::duration<Rep, Period>& rel_time);
`
[12](#cons-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9006)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#cons-12.sentence-1)
[13](#cons-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9011)
*Effects*: Calls m.try_lock_shared_for(rel_time)[.](#cons-13.sentence-1)
[14](#cons-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9015)
*Postconditions*: pm == addressof(m) and owns == res where res is
the value returned by the call to m.try_lock_shared_for(rel_time)[.](#cons-14.sentence-1)
[🔗](#lib:shared_lock,destructor)
`~shared_lock();
`
[15](#cons-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9028)
*Effects*: If owns calls pm->unlock_shared()[.](#cons-15.sentence-1)
[🔗](#lib:shared_lock,constructor_______)
`shared_lock(shared_lock&& sl) noexcept;
`
[16](#cons-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9039)
*Postconditions*: pm == sl_p.pm and owns == sl_p.owns (wheresl_p is the state of sl just prior to this construction),sl.pm == nullptr and sl.owns == false[.](#cons-16.sentence-1)
[🔗](#lib:operator=,shared_lock)
`shared_lock& operator=(shared_lock&& sl) noexcept;
`
[17](#cons-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9052)
*Effects*: Equivalent to: shared_lock(std::move(sl)).swap(*this)
[18](#cons-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9056)
*Returns*: *this[.](#cons-18.sentence-1)
#### [32.6.5.5.3](#locking) Locking [[thread.lock.shared.locking]](thread.lock.shared.locking)
[🔗](#lib:lock,shared_lock)
`void lock();
`
[1](#locking-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9069)
*Effects*: As if by pm->lock_shared()[.](#locking-1.sentence-1)
[2](#locking-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9073)
*Postconditions*: owns == true[.](#locking-2.sentence-1)
[3](#locking-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9077)
*Throws*: Any exception thrown by pm->lock_shared()[.](#locking-3.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-3.sentence-2)
[4](#locking-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9082)
*Error conditions*:
- [(4.1)](#locking-4.1)
operation_not_permitted — if pm is nullptr[.](#locking-4.1.sentence-1)
- [(4.2)](#locking-4.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-4.2.sentence-1)
[🔗](#lib:try_lock,shared_lock)
`bool try_lock();
`
[5](#locking-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9097)
*Effects*: As if by pm->try_lock_shared()[.](#locking-5.sentence-1)
[6](#locking-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9101)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared()[.](#locking-6.sentence-1)
[7](#locking-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9106)
*Returns*: The value returned by the call to pm->try_lock_shared()[.](#locking-7.sentence-1)
[8](#locking-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9110)
*Throws*: Any exception thrown by pm->try_lock_shared()[.](#locking-8.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-8.sentence-2)
[9](#locking-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9115)
*Error conditions*:
- [(9.1)](#locking-9.1)
operation_not_permitted — if pm is nullptr[.](#locking-9.1.sentence-1)
- [(9.2)](#locking-9.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-9.2.sentence-1)
[🔗](#lib:try_lock_until,shared_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[10](#locking-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9131)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#locking-10.sentence-1)
[11](#locking-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9136)
*Effects*: As if by pm->try_lock_shared_until(abs_time)[.](#locking-11.sentence-1)
[12](#locking-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9140)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared_until(abs_time)[.](#locking-12.sentence-1)
[13](#locking-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9145)
*Returns*: The value returned by the call topm->try_lock_shared_until(abs_time)[.](#locking-13.sentence-1)
[14](#locking-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9150)
*Throws*: Any exception thrown by pm->try_lock_shared_until(abs_time)[.](#locking-14.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-14.sentence-2)
[15](#locking-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9155)
*Error conditions*:
- [(15.1)](#locking-15.1)
operation_not_permitted — if pm is nullptr[.](#locking-15.1.sentence-1)
- [(15.2)](#locking-15.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-15.2.sentence-1)
[🔗](#lib:try_lock_for,shared_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[16](#locking-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9171)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#locking-16.sentence-1)
[17](#locking-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9176)
*Effects*: As if by pm->try_lock_shared_for(rel_time)[.](#locking-17.sentence-1)
[18](#locking-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9180)
*Postconditions*: owns == res, where res is the value returned by the call to pm->try_lock_shared_for(rel_time)[.](#locking-18.sentence-1)
[19](#locking-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9184)
*Returns*: The value returned by the call to pm->try_lock_shared_for(rel_time)[.](#locking-19.sentence-1)
[20](#locking-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9188)
*Throws*: Any exception thrown by pm->try_lock_shared_for(rel_time)[.](#locking-20.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-20.sentence-2)
[21](#locking-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9192)
*Error conditions*:
- [(21.1)](#locking-21.1)
operation_not_permitted — if pm is nullptr[.](#locking-21.1.sentence-1)
- [(21.2)](#locking-21.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-21.2.sentence-1)
[🔗](#lib:unlock,shared_lock)
`void unlock();
`
[22](#locking-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9207)
*Effects*: As if by pm->unlock_shared()[.](#locking-22.sentence-1)
[23](#locking-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9211)
*Postconditions*: owns == false[.](#locking-23.sentence-1)
[24](#locking-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9215)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-24.sentence-1)
[25](#locking-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9219)
*Error conditions*:
- [(25.1)](#locking-25.1)
operation_not_permitted — if on entry owns isfalse[.](#locking-25.sentence-1)
#### [32.6.5.5.4](#mod) Modifiers [[thread.lock.shared.mod]](thread.lock.shared.mod)
[🔗](#lib:swap,shared_lock)
`void swap(shared_lock& sl) noexcept;
`
[1](#mod-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9235)
*Effects*: Swaps the data members of *this and sl[.](#mod-1.sentence-1)
[🔗](#lib:release,shared_lock)
`mutex_type* release() noexcept;
`
[2](#mod-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9246)
*Postconditions*: pm == nullptr and owns == false[.](#mod-2.sentence-1)
[3](#mod-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9250)
*Returns*: The previous value of pm[.](#mod-3.sentence-1)
[🔗](#lib:swap,shared_lock_)
`template<class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
`
[4](#mod-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9262)
*Effects*: As if by x.swap(y)[.](#mod-4.sentence-1)
#### [32.6.5.5.5](#obs) Observers [[thread.lock.shared.obs]](thread.lock.shared.obs)
[🔗](#lib:owns_lock,shared_lock)
`bool owns_lock() const noexcept;
`
[1](#obs-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9275)
*Returns*: owns[.](#obs-1.sentence-1)
[🔗](#lib:operator_bool,shared_lock)
`explicit operator bool() const noexcept;
`
[2](#obs-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9286)
*Returns*: owns[.](#obs-2.sentence-1)
[🔗](#lib:mutex,shared_lock)
`mutex_type* mutex() const noexcept;
`
[3](#obs-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9297)
*Returns*: pm[.](#obs-3.sentence-1)

View File

@@ -0,0 +1,175 @@
[thread.lock.shared.cons]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared.cons)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared.cons)
#### 32.6.5.5 Class template shared_lock [[thread.lock.shared]](thread.lock.shared#cons)
#### 32.6.5.5.2 Constructors, destructor, and assignment [thread.lock.shared.cons]
[🔗](#lib:shared_lock,constructor)
`shared_lock() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8911)
*Postconditions*: pm == nullptr and owns == false[.](#1.sentence-1)
[🔗](#lib:shared_lock,constructor_)
`explicit shared_lock(mutex_type& m);
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8922)
*Effects*: Calls m.lock_shared()[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8926)
*Postconditions*: pm == addressof(m) and owns == true[.](#3.sentence-1)
[🔗](#lib:shared_lock,constructor__)
`shared_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8937)
*Postconditions*: pm == addressof(m) and owns == false[.](#4.sentence-1)
[🔗](#lib:shared_lock,constructor___)
`shared_lock(mutex_type& m, try_to_lock_t);
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8948)
*Effects*: Calls m.try_lock_shared()[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8952)
*Postconditions*: pm == addressof(m) and owns == res where res is the
value returned by the call to m.try_lock_shared()[.](#6.sentence-1)
[🔗](#lib:shared_lock,constructor____)
`shared_lock(mutex_type& m, adopt_lock_t);
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8965)
*Preconditions*: The calling thread holds a shared lock on m[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8969)
*Postconditions*: pm == addressof(m) and owns == true[.](#8.sentence-1)
[🔗](#lib:shared_lock,constructor_____)
`template<class Clock, class Duration>
shared_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& abs_time);
`
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8982)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8987)
*Effects*: Calls m.try_lock_shared_until(abs_time)[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8991)
*Postconditions*: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_lock_shared_until(abs_time)[.](#11.sentence-1)
[🔗](#lib:shared_lock,constructor______)
`template<class Rep, class Period>
shared_lock(mutex_type& m,
const chrono::duration<Rep, Period>& rel_time);
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9006)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9011)
*Effects*: Calls m.try_lock_shared_for(rel_time)[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9015)
*Postconditions*: pm == addressof(m) and owns == res where res is
the value returned by the call to m.try_lock_shared_for(rel_time)[.](#14.sentence-1)
[🔗](#lib:shared_lock,destructor)
`~shared_lock();
`
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9028)
*Effects*: If owns calls pm->unlock_shared()[.](#15.sentence-1)
[🔗](#lib:shared_lock,constructor_______)
`shared_lock(shared_lock&& sl) noexcept;
`
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9039)
*Postconditions*: pm == sl_p.pm and owns == sl_p.owns (wheresl_p is the state of sl just prior to this construction),sl.pm == nullptr and sl.owns == false[.](#16.sentence-1)
[🔗](#lib:operator=,shared_lock)
`shared_lock& operator=(shared_lock&& sl) noexcept;
`
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9052)
*Effects*: Equivalent to: shared_lock(std::move(sl)).swap(*this)
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9056)
*Returns*: *this[.](#18.sentence-1)

View File

@@ -0,0 +1,57 @@
[thread.lock.shared.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared.general)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared.general)
#### 32.6.5.5 Class template shared_lock [[thread.lock.shared]](thread.lock.shared#general)
#### 32.6.5.5.1 General [thread.lock.shared.general]
[🔗](#lib:shared_lock)
namespace std {template<class Mutex>class shared_lock {public:using mutex_type = Mutex; // [[thread.lock.shared.cons]](thread.lock.shared.cons "32.6.5.5.2Constructors, destructor, and assignment"), construct/copy/destroy shared_lock() noexcept; explicit shared_lock(mutex_type& m); // blocking shared_lock(mutex_type& m, defer_lock_t) noexcept;
shared_lock(mutex_type& m, try_to_lock_t);
shared_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~shared_lock();
shared_lock(const shared_lock&) = delete;
shared_lock& operator=(const shared_lock&) = delete;
shared_lock(shared_lock&& u) noexcept;
shared_lock& operator=(shared_lock&& u) noexcept; // [[thread.lock.shared.locking]](thread.lock.shared.locking "32.6.5.5.3Locking"), lockingvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.shared.mod]](thread.lock.shared.mod "32.6.5.5.4Modifiers"), modifiersvoid swap(shared_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.shared.obs]](thread.lock.shared.obs "32.6.5.5.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8881)
An object of type shared_lock controls the shared ownership of a
lockable object within a scope[.](#1.sentence-1)
Shared ownership of the lockable object may be
acquired at construction or after construction, and may be transferred, after
acquisition, to another shared_lock object[.](#1.sentence-2)
Objects of typeshared_lock are not copyable but are movable[.](#1.sentence-3)
The behavior of a program
is undefined if the contained pointer pm is not null and the lockable
object pointed to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the shared_lock object[.](#1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#1.sentence-5)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8893)
[*Note [1](#note-1)*:
shared_lock<Mutex> meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#2.sentence-1)
If Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements")),shared_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#2.sentence-2)
— *end note*]

View File

@@ -0,0 +1,234 @@
[thread.lock.shared.locking]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared.locking)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared.locking)
#### 32.6.5.5 Class template shared_lock [[thread.lock.shared]](thread.lock.shared#locking)
#### 32.6.5.5.3 Locking [thread.lock.shared.locking]
[🔗](#lib:lock,shared_lock)
`void lock();
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9069)
*Effects*: As if by pm->lock_shared()[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9073)
*Postconditions*: owns == true[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9077)
*Throws*: Any exception thrown by pm->lock_shared()[.](#3.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9082)
*Error conditions*:
- [(4.1)](#4.1)
operation_not_permitted — if pm is nullptr[.](#4.1.sentence-1)
- [(4.2)](#4.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#4.2.sentence-1)
[🔗](#lib:try_lock,shared_lock)
`bool try_lock();
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9097)
*Effects*: As if by pm->try_lock_shared()[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9101)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared()[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9106)
*Returns*: The value returned by the call to pm->try_lock_shared()[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9110)
*Throws*: Any exception thrown by pm->try_lock_shared()[.](#8.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#8.sentence-2)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9115)
*Error conditions*:
- [(9.1)](#9.1)
operation_not_permitted — if pm is nullptr[.](#9.1.sentence-1)
- [(9.2)](#9.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#9.2.sentence-1)
[🔗](#lib:try_lock_until,shared_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9131)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9136)
*Effects*: As if by pm->try_lock_shared_until(abs_time)[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9140)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared_until(abs_time)[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9145)
*Returns*: The value returned by the call topm->try_lock_shared_until(abs_time)[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9150)
*Throws*: Any exception thrown by pm->try_lock_shared_until(abs_time)[.](#14.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#14.sentence-2)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9155)
*Error conditions*:
- [(15.1)](#15.1)
operation_not_permitted — if pm is nullptr[.](#15.1.sentence-1)
- [(15.2)](#15.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#15.2.sentence-1)
[🔗](#lib:try_lock_for,shared_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9171)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#16.sentence-1)
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9176)
*Effects*: As if by pm->try_lock_shared_for(rel_time)[.](#17.sentence-1)
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9180)
*Postconditions*: owns == res, where res is the value returned by the call to pm->try_lock_shared_for(rel_time)[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9184)
*Returns*: The value returned by the call to pm->try_lock_shared_for(rel_time)[.](#19.sentence-1)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9188)
*Throws*: Any exception thrown by pm->try_lock_shared_for(rel_time)[.](#20.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#20.sentence-2)
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9192)
*Error conditions*:
- [(21.1)](#21.1)
operation_not_permitted — if pm is nullptr[.](#21.1.sentence-1)
- [(21.2)](#21.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#21.2.sentence-1)
[🔗](#lib:unlock,shared_lock)
`void unlock();
`
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9207)
*Effects*: As if by pm->unlock_shared()[.](#22.sentence-1)
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9211)
*Postconditions*: owns == false[.](#23.sentence-1)
[24](#24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9215)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#24.sentence-1)
[25](#25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9219)
*Error conditions*:
- [(25.1)](#25.1)
operation_not_permitted — if on entry owns isfalse[.](#25.sentence-1)

View File

@@ -0,0 +1,51 @@
[thread.lock.shared.mod]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared.mod)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared.mod)
#### 32.6.5.5 Class template shared_lock [[thread.lock.shared]](thread.lock.shared#mod)
#### 32.6.5.5.4 Modifiers [thread.lock.shared.mod]
[🔗](#lib:swap,shared_lock)
`void swap(shared_lock& sl) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9235)
*Effects*: Swaps the data members of *this and sl[.](#1.sentence-1)
[🔗](#lib:release,shared_lock)
`mutex_type* release() noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9246)
*Postconditions*: pm == nullptr and owns == false[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9250)
*Returns*: The previous value of pm[.](#3.sentence-1)
[🔗](#lib:swap,shared_lock_)
`template<class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9262)
*Effects*: As if by x.swap(y)[.](#4.sentence-1)

View File

@@ -0,0 +1,44 @@
[thread.lock.shared.obs]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.shared.obs)
### 32.6.5 Locks [[thread.lock]](thread.lock#shared.obs)
#### 32.6.5.5 Class template shared_lock [[thread.lock.shared]](thread.lock.shared#obs)
#### 32.6.5.5.5 Observers [thread.lock.shared.obs]
[🔗](#lib:owns_lock,shared_lock)
`bool owns_lock() const noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9275)
*Returns*: owns[.](#1.sentence-1)
[🔗](#lib:operator_bool,shared_lock)
`explicit operator bool() const noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9286)
*Returns*: owns[.](#2.sentence-1)
[🔗](#lib:mutex,shared_lock)
`mutex_type* mutex() const noexcept;
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9297)
*Returns*: pm[.](#3.sentence-1)

View File

@@ -0,0 +1,548 @@
[thread.lock.unique]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique)
#### 32.6.5.4 Class template unique_lock [thread.lock.unique]
#### [32.6.5.4.1](#general) General [[thread.lock.unique.general]](thread.lock.unique.general)
[🔗](#lib:unique_lock)
namespace std {template<class Mutex>class unique_lock {public:using mutex_type = Mutex; // [[thread.lock.unique.cons]](#cons "32.6.5.4.2Constructors, destructor, and assignment"), construct/copy/destroy unique_lock() noexcept; explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
unique_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~unique_lock();
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock(unique_lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u) noexcept; // [[thread.lock.unique.locking]](#locking "32.6.5.4.3Locking"), lockingvoid lock(); bool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.unique.mod]](#mod "32.6.5.4.4Modifiers"), modifiersvoid swap(unique_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.unique.obs]](#obs "32.6.5.4.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8399)
An object of type unique_lock controls the ownership of a lockable
object within a scope[.](#general-1.sentence-1)
Ownership of the lockable object may be acquired at
construction or after construction, and may be transferred, after
acquisition, to another unique_lock object[.](#general-1.sentence-2)
Objects of type unique_lock are not
copyable but are movable[.](#general-1.sentence-3)
The behavior of a program is undefined if the contained pointerpm is not null and the lockable object pointed
to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the unique_lock object[.](#general-1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#general-1.sentence-5)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8411)
[*Note [1](#general-note-1)*:
unique_lock<Mutex> meets the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements[.](#general-2.sentence-1)
If Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements")),unique_lock<Mutex> also meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements;
if Mutex meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements")),unique_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements[.](#general-2.sentence-2)
— *end note*]
#### [32.6.5.4.2](#cons) Constructors, destructor, and assignment [[thread.lock.unique.cons]](thread.lock.unique.cons)
[🔗](#lib:unique_lock,constructor)
`unique_lock() noexcept;
`
[1](#cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8429)
*Postconditions*: pm == nullptr and owns == false[.](#cons-1.sentence-1)
[🔗](#lib:unique_lock,constructor_)
`explicit unique_lock(mutex_type& m);
`
[2](#cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8440)
*Effects*: Calls m.lock()[.](#cons-2.sentence-1)
[3](#cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8444)
*Postconditions*: pm == addressof(m) and owns == true[.](#cons-3.sentence-1)
[🔗](#lib:unique_lock,constructor__)
`unique_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#cons-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8455)
*Postconditions*: pm == addressof(m) and owns == false[.](#cons-4.sentence-1)
[🔗](#lib:unique_lock,constructor___)
`unique_lock(mutex_type& m, try_to_lock_t);
`
[5](#cons-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8466)
*Preconditions*: The supplied Mutex type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#cons-5.sentence-1)
[6](#cons-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8471)
*Effects*: Calls m.try_lock()[.](#cons-6.sentence-1)
[7](#cons-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8475)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock()[.](#cons-7.sentence-1)
[🔗](#lib:unique_lock,constructor____)
`unique_lock(mutex_type& m, adopt_lock_t);
`
[8](#cons-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8487)
*Preconditions*: The calling thread holds a non-shared lock on m[.](#cons-8.sentence-1)
[9](#cons-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8491)
*Postconditions*: pm == addressof(m) and owns == true[.](#cons-9.sentence-1)
[10](#cons-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8495)
*Throws*: Nothing[.](#cons-10.sentence-1)
[🔗](#lib:unique_lock,constructor_____)
`template<class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#cons-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8507)
*Preconditions*: The supplied Mutex type meets the[*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#cons-11.sentence-1)
[12](#cons-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8512)
*Effects*: Calls m.try_lock_until(abs_time)[.](#cons-12.sentence-1)
[13](#cons-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8516)
*Postconditions*: pm == addressof(m) and owns == res,
where res is
the value returned by the call to m.try_lock_until(abs_time)[.](#cons-13.sentence-1)
[🔗](#lib:unique_lock,constructor______)
`template<class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
`
[14](#cons-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8530)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#cons-14.sentence-1)
[15](#cons-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8534)
*Effects*: Calls m.try_lock_for(rel_time)[.](#cons-15.sentence-1)
[16](#cons-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8538)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock_for(rel_time)[.](#cons-16.sentence-1)
[🔗](#lib:unique_lock,constructor_______)
`unique_lock(unique_lock&& u) noexcept;
`
[17](#cons-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8550)
*Postconditions*: pm == u_p.pm and owns == u_p.owns (where u_p is the state of u just prior to this construction), u.pm == 0 and u.owns == false[.](#cons-17.sentence-1)
[🔗](#lib:operator=,unique_lock)
`unique_lock& operator=(unique_lock&& u) noexcept;
`
[18](#cons-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8561)
*Effects*: Equivalent to: unique_lock(std::move(u)).swap(*this)
[19](#cons-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8565)
*Returns*: *this[.](#cons-19.sentence-1)
[🔗](#lib:unique_lock,destructor)
`~unique_lock();
`
[20](#cons-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8576)
*Effects*: If owns calls pm->unlock()[.](#cons-20.sentence-1)
#### [32.6.5.4.3](#locking) Locking [[thread.lock.unique.locking]](thread.lock.unique.locking)
[🔗](#lib:lock,unique_lock)
`void lock();
`
[1](#locking-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8589)
*Effects*: As if by pm->lock()[.](#locking-1.sentence-1)
[2](#locking-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8593)
*Postconditions*: owns == true[.](#locking-2.sentence-1)
[3](#locking-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8597)
*Throws*: Any exception thrown by pm->lock()[.](#locking-3.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-3.sentence-2)
[4](#locking-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8602)
*Error conditions*:
- [(4.1)](#locking-4.1)
operation_not_permitted — if pm is nullptr[.](#locking-4.1.sentence-1)
- [(4.2)](#locking-4.2)
resource_deadlock_would_occur — if on entry owns is true[.](#locking-4.2.sentence-1)
[🔗](#lib:try_lock,unique_lock)
`bool try_lock();
`
[5](#locking-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8617)
*Preconditions*: The supplied Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#locking-5.sentence-1)
[6](#locking-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8622)
*Effects*: As if by pm->try_lock()[.](#locking-6.sentence-1)
[7](#locking-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8626)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock()[.](#locking-7.sentence-1)
[8](#locking-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8631)
*Returns*: The value returned by pm->try_lock()[.](#locking-8.sentence-1)
[9](#locking-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8635)
*Throws*: Any exception thrown by pm->try_lock()[.](#locking-9.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-9.sentence-2)
[10](#locking-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8640)
*Error conditions*:
- [(10.1)](#locking-10.1)
operation_not_permitted — if pm is nullptr[.](#locking-10.1.sentence-1)
- [(10.2)](#locking-10.2)
resource_deadlock_would_occur — if on entry owns is true[.](#locking-10.2.sentence-1)
[🔗](#lib:try_lock_until,unique_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#locking-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8656)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#locking-11.sentence-1)
[12](#locking-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8661)
*Effects*: As if by pm->try_lock_until(abs_time)[.](#locking-12.sentence-1)
[13](#locking-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8665)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock_until(abs_time)[.](#locking-13.sentence-1)
[14](#locking-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8670)
*Returns*: The value returned by pm->try_lock_until(abs_time)[.](#locking-14.sentence-1)
[15](#locking-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8674)
*Throws*: Any exception thrown by pm->try_lock_until(abstime)[.](#locking-15.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-15.sentence-2)
[16](#locking-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8679)
*Error conditions*:
- [(16.1)](#locking-16.1)
operation_not_permitted — if pm is nullptr[.](#locking-16.1.sentence-1)
- [(16.2)](#locking-16.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-16.2.sentence-1)
[🔗](#lib:try_lock_for,unique_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[17](#locking-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8695)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#locking-17.sentence-1)
[18](#locking-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8699)
*Effects*: As if by pm->try_lock_for(rel_time)[.](#locking-18.sentence-1)
[19](#locking-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8703)
*Postconditions*: owns == res, where res is the value returned by pm->try_lock_for(rel_time)[.](#locking-19.sentence-1)
[20](#locking-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8707)
*Returns*: The value returned by pm->try_lock_for(rel_time)[.](#locking-20.sentence-1)
[21](#locking-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8711)
*Throws*: Any exception thrown by pm->try_lock_for(rel_time)[.](#locking-21.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-21.sentence-2)
[22](#locking-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8716)
*Error conditions*:
- [(22.1)](#locking-22.1)
operation_not_permitted — if pm is nullptr[.](#locking-22.1.sentence-1)
- [(22.2)](#locking-22.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#locking-22.2.sentence-1)
[🔗](#lib:unlock,unique_lock)
`void unlock();
`
[23](#locking-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8731)
*Effects*: As if by pm->unlock()[.](#locking-23.sentence-1)
[24](#locking-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8735)
*Postconditions*: owns == false[.](#locking-24.sentence-1)
[25](#locking-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8739)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#locking-25.sentence-1)
[26](#locking-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8744)
*Error conditions*:
- [(26.1)](#locking-26.1)
operation_not_permitted — if on entry owns is false[.](#locking-26.sentence-1)
#### [32.6.5.4.4](#mod) Modifiers [[thread.lock.unique.mod]](thread.lock.unique.mod)
[🔗](#lib:swap,unique_lock)
`void swap(unique_lock& u) noexcept;
`
[1](#mod-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8759)
*Effects*: Swaps the data members of *this and u[.](#mod-1.sentence-1)
[🔗](#lib:release,unique_lock)
`mutex_type* release() noexcept;
`
[2](#mod-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8770)
*Postconditions*: pm == 0 and owns == false[.](#mod-2.sentence-1)
[3](#mod-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8774)
*Returns*: The previous value of pm[.](#mod-3.sentence-1)
[🔗](#lib:swap,unique_lock_)
`template<class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
`
[4](#mod-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8786)
*Effects*: As if by x.swap(y)[.](#mod-4.sentence-1)
#### [32.6.5.4.5](#obs) Observers [[thread.lock.unique.obs]](thread.lock.unique.obs)
[🔗](#lib:owns_lock,unique_lock)
`bool owns_lock() const noexcept;
`
[1](#obs-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8799)
*Returns*: owns[.](#obs-1.sentence-1)
[🔗](#lib:operator_bool,unique_lock)
`explicit operator bool() const noexcept;
`
[2](#obs-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8810)
*Returns*: owns[.](#obs-2.sentence-1)
[🔗](#lib:mutex,unique_lock)
`mutex_type *mutex() const noexcept;
`
[3](#obs-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8821)
*Returns*: pm[.](#obs-3.sentence-1)

View File

@@ -0,0 +1,187 @@
[thread.lock.unique.cons]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique.cons)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique.cons)
#### 32.6.5.4 Class template unique_lock [[thread.lock.unique]](thread.lock.unique#cons)
#### 32.6.5.4.2 Constructors, destructor, and assignment [thread.lock.unique.cons]
[🔗](#lib:unique_lock,constructor)
`unique_lock() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8429)
*Postconditions*: pm == nullptr and owns == false[.](#1.sentence-1)
[🔗](#lib:unique_lock,constructor_)
`explicit unique_lock(mutex_type& m);
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8440)
*Effects*: Calls m.lock()[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8444)
*Postconditions*: pm == addressof(m) and owns == true[.](#3.sentence-1)
[🔗](#lib:unique_lock,constructor__)
`unique_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8455)
*Postconditions*: pm == addressof(m) and owns == false[.](#4.sentence-1)
[🔗](#lib:unique_lock,constructor___)
`unique_lock(mutex_type& m, try_to_lock_t);
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8466)
*Preconditions*: The supplied Mutex type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8471)
*Effects*: Calls m.try_lock()[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8475)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock()[.](#7.sentence-1)
[🔗](#lib:unique_lock,constructor____)
`unique_lock(mutex_type& m, adopt_lock_t);
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8487)
*Preconditions*: The calling thread holds a non-shared lock on m[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8491)
*Postconditions*: pm == addressof(m) and owns == true[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8495)
*Throws*: Nothing[.](#10.sentence-1)
[🔗](#lib:unique_lock,constructor_____)
`template<class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8507)
*Preconditions*: The supplied Mutex type meets the[*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8512)
*Effects*: Calls m.try_lock_until(abs_time)[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8516)
*Postconditions*: pm == addressof(m) and owns == res,
where res is
the value returned by the call to m.try_lock_until(abs_time)[.](#13.sentence-1)
[🔗](#lib:unique_lock,constructor______)
`template<class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
`
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8530)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8534)
*Effects*: Calls m.try_lock_for(rel_time)[.](#15.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8538)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock_for(rel_time)[.](#16.sentence-1)
[🔗](#lib:unique_lock,constructor_______)
`unique_lock(unique_lock&& u) noexcept;
`
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8550)
*Postconditions*: pm == u_p.pm and owns == u_p.owns (where u_p is the state of u just prior to this construction), u.pm == 0 and u.owns == false[.](#17.sentence-1)
[🔗](#lib:operator=,unique_lock)
`unique_lock& operator=(unique_lock&& u) noexcept;
`
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8561)
*Effects*: Equivalent to: unique_lock(std::move(u)).swap(*this)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8565)
*Returns*: *this[.](#19.sentence-1)
[🔗](#lib:unique_lock,destructor)
`~unique_lock();
`
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8576)
*Effects*: If owns calls pm->unlock()[.](#20.sentence-1)

View File

@@ -0,0 +1,59 @@
[thread.lock.unique.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique.general)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique.general)
#### 32.6.5.4 Class template unique_lock [[thread.lock.unique]](thread.lock.unique#general)
#### 32.6.5.4.1 General [thread.lock.unique.general]
[🔗](#lib:unique_lock)
namespace std {template<class Mutex>class unique_lock {public:using mutex_type = Mutex; // [[thread.lock.unique.cons]](thread.lock.unique.cons "32.6.5.4.2Constructors, destructor, and assignment"), construct/copy/destroy unique_lock() noexcept; explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
unique_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~unique_lock();
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock(unique_lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u) noexcept; // [[thread.lock.unique.locking]](thread.lock.unique.locking "32.6.5.4.3Locking"), lockingvoid lock(); bool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.unique.mod]](thread.lock.unique.mod "32.6.5.4.4Modifiers"), modifiersvoid swap(unique_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.unique.obs]](thread.lock.unique.obs "32.6.5.4.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8399)
An object of type unique_lock controls the ownership of a lockable
object within a scope[.](#1.sentence-1)
Ownership of the lockable object may be acquired at
construction or after construction, and may be transferred, after
acquisition, to another unique_lock object[.](#1.sentence-2)
Objects of type unique_lock are not
copyable but are movable[.](#1.sentence-3)
The behavior of a program is undefined if the contained pointerpm is not null and the lockable object pointed
to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the unique_lock object[.](#1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#1.sentence-5)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8411)
[*Note [1](#note-1)*:
unique_lock<Mutex> meets the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements[.](#2.sentence-1)
If Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements")),unique_lock<Mutex> also meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements;
if Mutex meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements")),unique_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements[.](#2.sentence-2)
— *end note*]

View File

@@ -0,0 +1,243 @@
[thread.lock.unique.locking]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique.locking)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique.locking)
#### 32.6.5.4 Class template unique_lock [[thread.lock.unique]](thread.lock.unique#locking)
#### 32.6.5.4.3 Locking [thread.lock.unique.locking]
[🔗](#lib:lock,unique_lock)
`void lock();
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8589)
*Effects*: As if by pm->lock()[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8593)
*Postconditions*: owns == true[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8597)
*Throws*: Any exception thrown by pm->lock()[.](#3.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8602)
*Error conditions*:
- [(4.1)](#4.1)
operation_not_permitted — if pm is nullptr[.](#4.1.sentence-1)
- [(4.2)](#4.2)
resource_deadlock_would_occur — if on entry owns is true[.](#4.2.sentence-1)
[🔗](#lib:try_lock,unique_lock)
`bool try_lock();
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8617)
*Preconditions*: The supplied Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8622)
*Effects*: As if by pm->try_lock()[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8626)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock()[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8631)
*Returns*: The value returned by pm->try_lock()[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8635)
*Throws*: Any exception thrown by pm->try_lock()[.](#9.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#9.sentence-2)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8640)
*Error conditions*:
- [(10.1)](#10.1)
operation_not_permitted — if pm is nullptr[.](#10.1.sentence-1)
- [(10.2)](#10.2)
resource_deadlock_would_occur — if on entry owns is true[.](#10.2.sentence-1)
[🔗](#lib:try_lock_until,unique_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8656)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8661)
*Effects*: As if by pm->try_lock_until(abs_time)[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8665)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock_until(abs_time)[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8670)
*Returns*: The value returned by pm->try_lock_until(abs_time)[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8674)
*Throws*: Any exception thrown by pm->try_lock_until(abstime)[.](#15.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#15.sentence-2)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8679)
*Error conditions*:
- [(16.1)](#16.1)
operation_not_permitted — if pm is nullptr[.](#16.1.sentence-1)
- [(16.2)](#16.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#16.2.sentence-1)
[🔗](#lib:try_lock_for,unique_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8695)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#17.sentence-1)
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8699)
*Effects*: As if by pm->try_lock_for(rel_time)[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8703)
*Postconditions*: owns == res, where res is the value returned by pm->try_lock_for(rel_time)[.](#19.sentence-1)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8707)
*Returns*: The value returned by pm->try_lock_for(rel_time)[.](#20.sentence-1)
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8711)
*Throws*: Any exception thrown by pm->try_lock_for(rel_time)[.](#21.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#21.sentence-2)
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8716)
*Error conditions*:
- [(22.1)](#22.1)
operation_not_permitted — if pm is nullptr[.](#22.1.sentence-1)
- [(22.2)](#22.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#22.2.sentence-1)
[🔗](#lib:unlock,unique_lock)
`void unlock();
`
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8731)
*Effects*: As if by pm->unlock()[.](#23.sentence-1)
[24](#24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8735)
*Postconditions*: owns == false[.](#24.sentence-1)
[25](#25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8739)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#25.sentence-1)
[26](#26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8744)
*Error conditions*:
- [(26.1)](#26.1)
operation_not_permitted — if on entry owns is false[.](#26.sentence-1)

View File

@@ -0,0 +1,51 @@
[thread.lock.unique.mod]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique.mod)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique.mod)
#### 32.6.5.4 Class template unique_lock [[thread.lock.unique]](thread.lock.unique#mod)
#### 32.6.5.4.4 Modifiers [thread.lock.unique.mod]
[🔗](#lib:swap,unique_lock)
`void swap(unique_lock& u) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8759)
*Effects*: Swaps the data members of *this and u[.](#1.sentence-1)
[🔗](#lib:release,unique_lock)
`mutex_type* release() noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8770)
*Postconditions*: pm == 0 and owns == false[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8774)
*Returns*: The previous value of pm[.](#3.sentence-1)
[🔗](#lib:swap,unique_lock_)
`template<class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8786)
*Effects*: As if by x.swap(y)[.](#4.sentence-1)

View File

@@ -0,0 +1,44 @@
[thread.lock.unique.obs]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.lock.unique.obs)
### 32.6.5 Locks [[thread.lock]](thread.lock#unique.obs)
#### 32.6.5.4 Class template unique_lock [[thread.lock.unique]](thread.lock.unique#obs)
#### 32.6.5.4.5 Observers [thread.lock.unique.obs]
[🔗](#lib:owns_lock,unique_lock)
`bool owns_lock() const noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8799)
*Returns*: owns[.](#1.sentence-1)
[🔗](#lib:operator_bool,unique_lock)
`explicit operator bool() const noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8810)
*Returns*: owns[.](#2.sentence-1)
[🔗](#lib:mutex,unique_lock)
`mutex_type *mutex() const noexcept;
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8821)
*Returns*: pm[.](#3.sentence-1)

2546
cppdraft/thread/mutex.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
[thread.mutex.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#class)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.mutex.class)
#### 32.6.4.2 Mutex types [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex#thread.mutex.class)
#### 32.6.4.2.2 Class mutex [thread.mutex.class]
[🔗](#lib:mutex)
namespace std {class mutex {public:constexpr mutex() noexcept; ~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7508)
The class mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#1.sentence-1)
If one thread owns a mutex object, attempts by another thread to acquire
ownership of that object will fail (for try_lock()) or block (forlock()) until the owning thread has released ownership with a call tounlock()[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7516)
[*Note [1](#note-1)*:
After a thread A has called unlock(), releasing a mutex, it is possible for another
thread B to lock the same mutex, observe that it is no longer in use, unlock it, and
destroy it, before thread A appears to have returned from its unlock call[.](#2.sentence-1)
Conforming implementations
handle such scenarios correctly, as long as thread A does not access the
mutex after the unlock call returns[.](#2.sentence-2)
These cases typically occur when a reference-counted object
contains a mutex that is used to protect the reference count[.](#2.sentence-3)
— *end note*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7526)
The class mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](thread.mutex.requirements "32.6.4Mutex requirements"))[.](#3.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7531)
[*Note [2](#note-2)*:
A program can deadlock if the thread that owns a mutex object callslock() on that object[.](#4.sentence-1)
If the implementation can detect the deadlock,
a resource_deadlock_would_occur error condition might be observed[.](#4.sentence-2)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7538)
The behavior of a program is undefined if
it destroys a mutex object owned by any thread or
a thread terminates while owning a mutex object[.](#5.sentence-1)

View File

@@ -0,0 +1,17 @@
[thread.mutex.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#general)
### 32.6.1 General [thread.mutex.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7252)
Subclause [[thread.mutex]](thread.mutex "32.6Mutual exclusion") provides mechanisms for mutual exclusion: mutexes, locks, and call
once[.](#1.sentence-1)
These mechanisms ease the production of race-free
programs ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#1.sentence-2)

View File

@@ -0,0 +1,71 @@
[thread.mutex.recursive]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#recursive)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.mutex.recursive)
#### 32.6.4.2 Mutex types [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex#thread.mutex.recursive)
#### 32.6.4.2.3 Class recursive_mutex [thread.mutex.recursive]
[🔗](#lib:recursive_mutex)
namespace std {class recursive_mutex {public: recursive_mutex(); ~recursive_mutex();
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock() noexcept; void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7566)
The class recursive_mutex provides a recursive mutex with exclusive ownership
semantics[.](#1.sentence-1)
If one thread owns a recursive_mutex object, attempts by another
thread to acquire ownership of that object will fail (for try_lock()) or block
(for lock()) until the first thread has completely released ownership[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7573)
The class recursive_mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](thread.mutex.requirements "32.6.4Mutex requirements"))[.](#2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7578)
A thread that owns a recursive_mutex object may acquire additional levels of
ownership by calling lock() or try_lock() on that object[.](#3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#3.sentence-2)
If a thread
has already acquired the maximum level of ownership for a recursive_mutex object, additional calls to try_lock() fail, and additional calls tolock() throw an exception of type system_error[.](#3.sentence-3)
A thread
shall call unlock() once for each level of ownership acquired by calls tolock() and try_lock()[.](#3.sentence-4)
Only when all levels of ownership have been
released may ownership be acquired by another thread[.](#3.sentence-5)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7589)
The behavior of a program is undefined if
- [(4.1)](#4.1)
it destroys a recursive_mutex object owned by any thread or
- [(4.2)](#4.2)
a thread terminates while owning a recursive_mutex object[.](#4.sentence-1)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
[thread.mutex.requirements.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#requirements.general)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#general)
#### 32.6.4.1 General [thread.mutex.requirements.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7318)
A mutex object facilitates protection against data races and allows safe synchronization of
data between [execution agents](thread.req.lockable#def:execution_agent "32.2.5Requirements for Cpp17Lockable types[thread.req.lockable]")[.](#1.sentence-1)
An execution agent [*owns*](#def:owns) a mutex from the time it successfully calls one of the
lock functions until it calls unlock[.](#1.sentence-2)
Mutexes can be either recursive or non-recursive, and can
grant simultaneous ownership to one or many execution agents[.](#1.sentence-3)
Both
recursive and non-recursive mutexes are supplied[.](#1.sentence-4)

View File

@@ -0,0 +1,382 @@
[thread.mutex.requirements.mutex]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#requirements.mutex)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#mutex)
#### 32.6.4.2 Mutex types [thread.mutex.requirements.mutex]
#### [32.6.4.2.1](#general) General [[thread.mutex.requirements.mutex.general]](thread.mutex.requirements.mutex.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7330)
The [*mutex types*](#def:mutex_types "32.6.4.2.1General[thread.mutex.requirements.mutex.general]") are the standard library types mutex,recursive_mutex, timed_mutex, recursive_timed_mutex,shared_mutex, and shared_timed_mutex[.](#general-1.sentence-1)
They meet the requirements set out in [thread.mutex.requirements.mutex][.](#general-1.sentence-2)
In this description, m denotes an object of a mutex type[.](#general-1.sentence-3)
[*Note [1](#general-note-1)*:
The mutex types meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#general-1.sentence-4)
— *end note*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7340)
The mutex types meet [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]")[.](#general-2.sentence-1)
If initialization of an object of a mutex type fails,
an exception of type system_error is thrown[.](#general-2.sentence-2)
The mutex types are neither copyable nor movable[.](#general-2.sentence-3)
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7346)
The error conditions for error codes, if any, reported by member functions of the mutex types
are as follows:
- [(3.1)](#general-3.1)
resource_unavailable_try_again — if any native handle type manipulated is not available[.](#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)
- [(3.3)](#general-3.3)
invalid_argument — if any native handle type manipulated as part of mutex
construction is incorrect[.](#general-3.3.sentence-1)
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7357)
The implementation provides lock and unlock operations, as described below[.](#general-4.sentence-1)
For purposes of determining the existence of a data race, these behave as
atomic operations ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#general-4.sentence-2)
The lock and unlock operations on
a single mutex appears to occur in a single total order[.](#general-4.sentence-3)
[*Note [2](#general-note-2)*:
This
can be viewed as the [modification order](intro.multithread#def:modification_order "6.10.2Multi-threaded executions and data races[intro.multithread]") of the
mutex[.](#general-4.sentence-4)
— *end note*]
[*Note [3](#general-note-3)*:
Construction and
destruction of an object of a mutex type need not be thread-safe; other
synchronization can be used to ensure that mutex objects are initialized
and visible to other threads[.](#general-4.sentence-5)
— *end note*]
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7374)
The expression m.lock() is well-formed and has the following semantics:
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7377)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#general-6.sentence-1)
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7383)
*Effects*: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7388)
*Synchronization*: Prior unlock() operations on the same object[*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#general-8.sentence-1)
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7393)
*Postconditions*: The calling thread owns the mutex[.](#general-9.sentence-1)
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7397)
*Return type*: void[.](#general-10.sentence-1)
[11](#general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7400)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#general-11.sentence-1)
[12](#general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7405)
*Error conditions*:
- [(12.1)](#general-12.1)
operation_not_permitted — if the thread does not have the
privilege to perform the operation[.](#general-12.1.sentence-1)
- [(12.2)](#general-12.2)
resource_deadlock_would_occur — if the implementation detects
that a deadlock would occur[.](#general-12.2.sentence-1)
[13](#general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7416)
The expression m.try_lock() is well-formed and has the following semantics:
[14](#general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7419)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#general-14.sentence-1)
[15](#general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7425)
*Effects*: Attempts to obtain ownership of the mutex for the calling thread without
blocking[.](#general-15.sentence-1)
If ownership is not obtained, there is no effect and try_lock() immediately returns[.](#general-15.sentence-2)
An implementation may fail to obtain the lock even if it is not
held by any other thread[.](#general-15.sentence-3)
[*Note [4](#general-note-4)*:
This spurious failure is normally uncommon, but
allows interesting implementations based on a simple
compare and exchange ([[atomics]](atomics "32.5Atomic operations"))[.](#general-15.sentence-4)
— *end note*]
An implementation should ensure that try_lock() does not consistently return false in the absence of contending mutex acquisitions[.](#general-15.sentence-5)
[16](#general-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7439)
*Synchronization*: If try_lock() returns true, prior unlock() operations
on the same object [synchronize with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") this operation[.](#general-16.sentence-1)
[*Note [5](#general-note-5)*:
Since lock() does not synchronize with a failed subsequenttry_lock(), the visibility rules are weak enough that little would be
known about the state after a failure, even in the absence of spurious failures[.](#general-16.sentence-2)
— *end note*]
[17](#general-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7449)
*Return type*: bool[.](#general-17.sentence-1)
[18](#general-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7452)
*Returns*: true if ownership was obtained, otherwise false[.](#general-18.sentence-1)
[19](#general-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7456)
*Throws*: Nothing[.](#general-19.sentence-1)
[20](#general-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7461)
The expression m.unlock() is well-formed and has the following semantics:
[21](#general-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7464)
*Preconditions*: The calling thread owns the mutex[.](#general-21.sentence-1)
[22](#general-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7468)
*Effects*: Releases the calling thread's ownership of the mutex[.](#general-22.sentence-1)
[23](#general-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7472)
*Return type*: void[.](#general-23.sentence-1)
[24](#general-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7475)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequent
lock operations that obtain ownership on the same object[.](#general-24.sentence-1)
[25](#general-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7480)
*Throws*: Nothing[.](#general-25.sentence-1)
#### [32.6.4.2.2](#thread.mutex.class) Class mutex [[thread.mutex.class]](thread.mutex.class)
[🔗](#lib:mutex)
namespace std {class mutex {public:constexpr mutex() noexcept; ~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.mutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7508)
The class mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#thread.mutex.class-1.sentence-1)
If one thread owns a mutex object, attempts by another thread to acquire
ownership of that object will fail (for try_lock()) or block (forlock()) until the owning thread has released ownership with a call tounlock()[.](#thread.mutex.class-1.sentence-2)
[2](#thread.mutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7516)
[*Note [1](#thread.mutex.class-note-1)*:
After a thread A has called unlock(), releasing a mutex, it is possible for another
thread B to lock the same mutex, observe that it is no longer in use, unlock it, and
destroy it, before thread A appears to have returned from its unlock call[.](#thread.mutex.class-2.sentence-1)
Conforming implementations
handle such scenarios correctly, as long as thread A does not access the
mutex after the unlock call returns[.](#thread.mutex.class-2.sentence-2)
These cases typically occur when a reference-counted object
contains a mutex that is used to protect the reference count[.](#thread.mutex.class-2.sentence-3)
— *end note*]
[3](#thread.mutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7526)
The class mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](thread.mutex.requirements "32.6.4Mutex requirements"))[.](#thread.mutex.class-3.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.mutex.class-3.sentence-2)
[4](#thread.mutex.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7531)
[*Note [2](#thread.mutex.class-note-2)*:
A program can deadlock if the thread that owns a mutex object callslock() on that object[.](#thread.mutex.class-4.sentence-1)
If the implementation can detect the deadlock,
a resource_deadlock_would_occur error condition might be observed[.](#thread.mutex.class-4.sentence-2)
— *end note*]
[5](#thread.mutex.class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7538)
The behavior of a program is undefined if
it destroys a mutex object owned by any thread or
a thread terminates while owning a mutex object[.](#thread.mutex.class-5.sentence-1)
#### [32.6.4.2.3](#thread.mutex.recursive) Class recursive_mutex [[thread.mutex.recursive]](thread.mutex.recursive)
[🔗](#lib:recursive_mutex)
namespace std {class recursive_mutex {public: recursive_mutex(); ~recursive_mutex();
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock() noexcept; void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.mutex.recursive-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7566)
The class recursive_mutex provides a recursive mutex with exclusive ownership
semantics[.](#thread.mutex.recursive-1.sentence-1)
If one thread owns a recursive_mutex object, attempts by another
thread to acquire ownership of that object will fail (for try_lock()) or block
(for lock()) until the first thread has completely released ownership[.](#thread.mutex.recursive-1.sentence-2)
[2](#thread.mutex.recursive-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7573)
The class recursive_mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](thread.mutex.requirements "32.6.4Mutex requirements"))[.](#thread.mutex.recursive-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.mutex.recursive-2.sentence-2)
[3](#thread.mutex.recursive-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7578)
A thread that owns a recursive_mutex object may acquire additional levels of
ownership by calling lock() or try_lock() on that object[.](#thread.mutex.recursive-3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#thread.mutex.recursive-3.sentence-2)
If a thread
has already acquired the maximum level of ownership for a recursive_mutex object, additional calls to try_lock() fail, and additional calls tolock() throw an exception of type system_error[.](#thread.mutex.recursive-3.sentence-3)
A thread
shall call unlock() once for each level of ownership acquired by calls tolock() and try_lock()[.](#thread.mutex.recursive-3.sentence-4)
Only when all levels of ownership have been
released may ownership be acquired by another thread[.](#thread.mutex.recursive-3.sentence-5)
[4](#thread.mutex.recursive-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7589)
The behavior of a program is undefined if
- [(4.1)](#thread.mutex.recursive-4.1)
it destroys a recursive_mutex object owned by any thread or
- [(4.2)](#thread.mutex.recursive-4.2)
a thread terminates while owning a recursive_mutex object[.](#thread.mutex.recursive-4.sentence-1)

View File

@@ -0,0 +1,252 @@
[thread.mutex.requirements.mutex.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#requirements.mutex.general)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#mutex.general)
#### 32.6.4.2 Mutex types [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex#general)
#### 32.6.4.2.1 General [thread.mutex.requirements.mutex.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7330)
The [*mutex types*](#def:mutex_types "32.6.4.2.1General[thread.mutex.requirements.mutex.general]") are the standard library types mutex,recursive_mutex, timed_mutex, recursive_timed_mutex,shared_mutex, and shared_timed_mutex[.](#1.sentence-1)
They meet the requirements set out in [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types")[.](#1.sentence-2)
In this description, m denotes an object of a mutex type[.](#1.sentence-3)
[*Note [1](#note-1)*:
The mutex types meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#1.sentence-4)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7340)
The mutex types meet [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]")[.](#2.sentence-1)
If initialization of an object of a mutex type fails,
an exception of type system_error is thrown[.](#2.sentence-2)
The mutex types are neither copyable nor movable[.](#2.sentence-3)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7346)
The error conditions for error codes, if any, reported by member functions of the mutex types
are as follows:
- [(3.1)](#3.1)
resource_unavailable_try_again — if any native handle type manipulated is not available[.](#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)
- [(3.3)](#3.3)
invalid_argument — if any native handle type manipulated as part of mutex
construction is incorrect[.](#3.3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7357)
The implementation provides lock and unlock operations, as described below[.](#4.sentence-1)
For purposes of determining the existence of a data race, these behave as
atomic operations ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#4.sentence-2)
The lock and unlock operations on
a single mutex appears to occur in a single total order[.](#4.sentence-3)
[*Note [2](#note-2)*:
This
can be viewed as the [modification order](intro.multithread#def:modification_order "6.10.2Multi-threaded executions and data races[intro.multithread]") of the
mutex[.](#4.sentence-4)
— *end note*]
[*Note [3](#note-3)*:
Construction and
destruction of an object of a mutex type need not be thread-safe; other
synchronization can be used to ensure that mutex objects are initialized
and visible to other threads[.](#4.sentence-5)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7374)
The expression m.lock() is well-formed and has the following semantics:
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7377)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7383)
*Effects*: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7388)
*Synchronization*: Prior unlock() operations on the same object[*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7393)
*Postconditions*: The calling thread owns the mutex[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7397)
*Return type*: void[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7400)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7405)
*Error conditions*:
- [(12.1)](#12.1)
operation_not_permitted — if the thread does not have the
privilege to perform the operation[.](#12.1.sentence-1)
- [(12.2)](#12.2)
resource_deadlock_would_occur — if the implementation detects
that a deadlock would occur[.](#12.2.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7416)
The expression m.try_lock() is well-formed and has the following semantics:
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7419)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7425)
*Effects*: Attempts to obtain ownership of the mutex for the calling thread without
blocking[.](#15.sentence-1)
If ownership is not obtained, there is no effect and try_lock() immediately returns[.](#15.sentence-2)
An implementation may fail to obtain the lock even if it is not
held by any other thread[.](#15.sentence-3)
[*Note [4](#note-4)*:
This spurious failure is normally uncommon, but
allows interesting implementations based on a simple
compare and exchange ([[atomics]](atomics "32.5Atomic operations"))[.](#15.sentence-4)
— *end note*]
An implementation should ensure that try_lock() does not consistently return false in the absence of contending mutex acquisitions[.](#15.sentence-5)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7439)
*Synchronization*: If try_lock() returns true, prior unlock() operations
on the same object [synchronize with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") this operation[.](#16.sentence-1)
[*Note [5](#note-5)*:
Since lock() does not synchronize with a failed subsequenttry_lock(), the visibility rules are weak enough that little would be
known about the state after a failure, even in the absence of spurious failures[.](#16.sentence-2)
— *end note*]
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7449)
*Return type*: bool[.](#17.sentence-1)
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7452)
*Returns*: true if ownership was obtained, otherwise false[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7456)
*Throws*: Nothing[.](#19.sentence-1)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7461)
The expression m.unlock() is well-formed and has the following semantics:
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7464)
*Preconditions*: The calling thread owns the mutex[.](#21.sentence-1)
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7468)
*Effects*: Releases the calling thread's ownership of the mutex[.](#22.sentence-1)
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7472)
*Return type*: void[.](#23.sentence-1)
[24](#24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7475)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequent
lock operations that obtain ownership on the same object[.](#24.sentence-1)
[25](#25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7480)
*Throws*: Nothing[.](#25.sentence-1)

109
cppdraft/thread/once.md Normal file
View File

@@ -0,0 +1,109 @@
[thread.once]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.once)
### 32.6.7 Call once [thread.once]
#### [32.6.7.1](#onceflag) Struct once_flag [[thread.once.onceflag]](thread.once.onceflag)
[🔗](#lib:once_flag)
namespace std {struct once_flag {constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete; };}
[1](#onceflag-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9379)
The class once_flag is an opaque data structure that call_once uses to
initialize data without causing a data race or deadlock[.](#onceflag-1.sentence-1)
[🔗](#lib:once_flag_)
`constexpr once_flag() noexcept;
`
[2](#onceflag-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9389)
*Synchronization*: The construction of a once_flag object is not synchronized[.](#onceflag-2.sentence-1)
[3](#onceflag-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9393)
*Postconditions*: The object's internal state is set to indicate to an invocation ofcall_once with the object as its initial argument that no function has been
called[.](#onceflag-3.sentence-1)
#### [32.6.7.2](#callonce) Function call_once [[thread.once.callonce]](thread.once.callonce)
[🔗](#lib:call_once)
`template<class Callable, class... Args>
void call_once(once_flag& flag, Callable&& func, Args&&... args);
`
[1](#callonce-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9409)
*Mandates*: is_invocable_v<Callable, Args...> is true[.](#callonce-1.sentence-1)
[2](#callonce-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9413)
*Effects*: An execution of call_once that does not call its func is a[*passive*](#def:passive) execution[.](#callonce-2.sentence-1)
An execution of call_once that calls its func is an [*active*](#def:active) execution[.](#callonce-2.sentence-2)
An active execution evaluates*INVOKE*(std::forward<Callable>(func),
std::forward<Args>(args)...) ([[func.require]](func.require "22.10.4Requirements"))[.](#callonce-2.sentence-3)
If such a call to func throws an exception the execution is [*exceptional*](#def:exceptional), otherwise it is [*returning*](#def:returning)[.](#callonce-2.sentence-4)
An exceptional execution propagates the exception to the caller ofcall_once[.](#callonce-2.sentence-5)
Among all executions of call_once for any givenonce_flag: at most one is a returning execution; if there is a
returning execution, it is the last active execution; and there are
passive executions only if there is a returning execution[.](#callonce-2.sentence-6)
[*Note [1](#callonce-note-1)*:
Passive
executions allow other threads to reliably observe the results produced by the
earlier returning execution[.](#callonce-2.sentence-7)
— *end note*]
[3](#callonce-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9433)
*Synchronization*: For any given once_flag: all active executions occur in a total
order; completion of an active execution [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") the start of the next one in this total order; and the returning execution
synchronizes with the return from all passive executions[.](#callonce-3.sentence-1)
[4](#callonce-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9440)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions")), or any exception thrown by func[.](#callonce-4.sentence-1)
[5](#callonce-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9445)
[*Example [1](#callonce-example-1)*: // global flag, regular functionvoid init();
std::once_flag flag;
void f() { std::call_once(flag, init);}// function static flag, function objectstruct initializer {void operator()();};
void g() {static std::once_flag flag2;
std::call_once(flag2, initializer());}// object flag, member functionclass information { std::once_flag verified; void verifier();public:void verify() { std::call_once(verified, &information::verifier, *this); }}; — *end example*]

View File

@@ -0,0 +1,75 @@
[thread.once.callonce]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.once.callonce)
### 32.6.7 Call once [[thread.once]](thread.once#callonce)
#### 32.6.7.2 Function call_once [thread.once.callonce]
[🔗](#lib:call_once)
`template<class Callable, class... Args>
void call_once(once_flag& flag, Callable&& func, Args&&... args);
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9409)
*Mandates*: is_invocable_v<Callable, Args...> is true[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9413)
*Effects*: An execution of call_once that does not call its func is a[*passive*](#def:passive) execution[.](#2.sentence-1)
An execution of call_once that calls its func is an [*active*](#def:active) execution[.](#2.sentence-2)
An active execution evaluates*INVOKE*(std::forward<Callable>(func),
std::forward<Args>(args)...) ([[func.require]](func.require "22.10.4Requirements"))[.](#2.sentence-3)
If such a call to func throws an exception the execution is [*exceptional*](#def:exceptional), otherwise it is [*returning*](#def:returning)[.](#2.sentence-4)
An exceptional execution propagates the exception to the caller ofcall_once[.](#2.sentence-5)
Among all executions of call_once for any givenonce_flag: at most one is a returning execution; if there is a
returning execution, it is the last active execution; and there are
passive executions only if there is a returning execution[.](#2.sentence-6)
[*Note [1](#note-1)*:
Passive
executions allow other threads to reliably observe the results produced by the
earlier returning execution[.](#2.sentence-7)
— *end note*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9433)
*Synchronization*: For any given once_flag: all active executions occur in a total
order; completion of an active execution [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") the start of the next one in this total order; and the returning execution
synchronizes with the return from all passive executions[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9440)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions")), or any exception thrown by func[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9445)
[*Example [1](#example-1)*: // global flag, regular functionvoid init();
std::once_flag flag;
void f() { std::call_once(flag, init);}// function static flag, function objectstruct initializer {void operator()();};
void g() {static std::once_flag flag2;
std::call_once(flag2, initializer());}// object flag, member functionclass information { std::once_flag verified; void verifier();public:void verify() { std::call_once(verified, &information::verifier, *this); }}; — *end example*]

View File

@@ -0,0 +1,41 @@
[thread.once.onceflag]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.once.onceflag)
### 32.6.7 Call once [[thread.once]](thread.once#onceflag)
#### 32.6.7.1 Struct once_flag [thread.once.onceflag]
[🔗](#lib:once_flag)
namespace std {struct once_flag {constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete; };}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9379)
The class once_flag is an opaque data structure that call_once uses to
initialize data without causing a data race or deadlock[.](#1.sentence-1)
[🔗](#lib:once_flag_)
`constexpr once_flag() noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9389)
*Synchronization*: The construction of a once_flag object is not synchronized[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9393)
*Postconditions*: The object's internal state is set to indicate to an invocation ofcall_once with the object as its initial argument that no function has been
called[.](#3.sentence-1)

576
cppdraft/thread/req.md Normal file
View File

@@ -0,0 +1,576 @@
[thread.req]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [thread.req]
### [32.2.1](#paramname) Template parameter names [[thread.req.paramname]](thread.req.paramname)
[1](#paramname-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L31)
Throughout this Clause, the names of template parameters are used to express type
requirements[.](#paramname-1.sentence-1)
Predicate is a function object type ([[function.objects]](function.objects "22.10Function objects"))[.](#paramname-1.sentence-2)
Let pred denote an lvalue of type Predicate[.](#paramname-1.sentence-3)
Then the expression pred() shall be well-formed and
the type decltype(pred()) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2Boolean testability"))[.](#paramname-1.sentence-4)
The return value of pred(), converted to bool,
yields true if the corresponding test condition is satisfied, andfalse otherwise[.](#paramname-1.sentence-5)
If a template parameter is named Clock,
the corresponding template argument shall be a type C that meets the [*Cpp17Clock*](time.clock.req#:Cpp17Clock "30.3Cpp17Clock requirements[time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3Cpp17Clock requirements"));
the program is ill-formed if is_clock_v<C> is false[.](#paramname-1.sentence-6)
### [32.2.2](#exception) Exceptions [[thread.req.exception]](thread.req.exception)
[1](#exception-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L49)
Some functions described in this Clause are specified to throw exceptions of typesystem_error ([[syserr.syserr]](syserr.syserr "19.5.8Class system_­error"))[.](#exception-1.sentence-1)
Such exceptions are thrown if
any of the function's error conditions is detected or
a call to
an operating system or other underlying API results in an error that prevents the
library function from
meeting its specifications[.](#exception-1.sentence-2)
Failure to allocate storage is reported as described
in [[res.on.exception.handling]](res.on.exception.handling "16.4.6.14Restrictions on exception handling")[.](#exception-1.sentence-3)
[*Example [1](#exception-example-1)*:
Consider a function in this Clause that is specified to throw exceptions of typesystem_error and specifies error conditions that includeoperation_not_permitted for a thread that does not have the privilege to
perform the operation[.](#exception-1.sentence-4)
Assume that, during the execution of this function, an errno of EPERM is reported by a POSIX API call used by the implementation[.](#exception-1.sentence-5)
Since POSIX
specifies an errno of EPERM when “the caller does not have the privilege
to perform the operation”, the implementation maps EPERM to anerror_condition of operation_not_permitted ([[syserr]](syserr "19.5System error support")) and an exception
of type system_error is thrown[.](#exception-1.sentence-6)
— *end example*]
[2](#exception-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L71)
The error_code reported by such an exception's code() member function
compares equal to one of the conditions specified in the function's error condition
element[.](#exception-2.sentence-1)
### [32.2.3](#native) Native handles [[thread.req.native]](thread.req.native)
[1](#native-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L78)
Several classes described in this Clause have members native_handle_type andnative_handle[.](#native-1.sentence-1)
The presence of these members and their semantics isimplementation-defined[.](#native-1.sentence-2)
[*Note [1](#native-note-1)*:
These members allow implementations to provide access
to implementation details[.](#native-1.sentence-3)
Their names are specified to facilitate portable compile-time
detection[.](#native-1.sentence-4)
Actual use of these members is inherently non-portable[.](#native-1.sentence-5)
— *end note*]
### [32.2.4](#timing) Timing specifications [[thread.req.timing]](thread.req.timing)
[1](#timing-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L90)
Several functions described in this Clause take an argument to specify a timeout[.](#timing-1.sentence-1)
These
timeouts are specified as either a duration or a time_point type as
specified in [[time]](time "30Time library")[.](#timing-1.sentence-2)
[2](#timing-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L95)
Implementations necessarily have some delay in returning from a timeout[.](#timing-2.sentence-1)
Any overhead in
interrupt response, function return, and scheduling induces a “quality of implementation”
delay, expressed as duration Di[.](#timing-2.sentence-2)
Ideally, this delay would be zero[.](#timing-2.sentence-3)
Further, any contention for
processor and memory resources induces a “quality of management” delay, expressed as durationDm[.](#timing-2.sentence-4)
The delay durations may vary from timeout to timeout, but in all cases shorter is better[.](#timing-2.sentence-5)
[3](#timing-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L102)
The functions whose names end in _for take an argument that
specifies a duration[.](#timing-3.sentence-1)
These functions produce relative timeouts[.](#timing-3.sentence-2)
Implementations
should use a steady clock to measure time for these functions[.](#timing-3.sentence-3)[293](#footnote-293 "Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation.")
Given a duration
argument Dt, the real-time duration of the timeout is Dt+Di+Dm[.](#timing-3.sentence-4)
[4](#timing-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L113)
The functions whose names end in _until take an argument that specifies a time
point[.](#timing-4.sentence-1)
These functions produce absolute timeouts[.](#timing-4.sentence-2)
Implementations should use the clock
specified in the time point to measure time for these functions[.](#timing-4.sentence-3)
Given a clock time point
argument Ct, the clock time point of the return from timeout should be Ct+Di+Dm when the clock is not adjusted during the timeout[.](#timing-4.sentence-4)
If the clock is adjusted to the time Ca during the timeout, the behavior should be as follows:
- [(4.1)](#timing-4.1)
If Ca>Ct, the waiting function should wake as soon as possible, i.e., Ca+Di+Dm,
since the timeout is already satisfied[.](#timing-4.1.sentence-1)
This specification may result in the total
duration of the wait decreasing when measured against a steady clock[.](#timing-4.1.sentence-2)
- [(4.2)](#timing-4.2)
If Ca≤Ct, the waiting function should not time out until Clock::now() returns a
time Cn≥Ct, i.e., waking at Ct+Di+Dm[.](#timing-4.2.sentence-1)
[*Note [1](#timing-note-1)*:
When the clock is adjusted
backwards, this specification can result in the total duration of the wait increasing when
measured against a steady clock[.](#timing-4.2.sentence-2)
When the clock is adjusted forwards, this specification can
result in the total duration of the wait decreasing when measured against a steady clock[.](#timing-4.2.sentence-3)
— *end note*]
An implementation returns from such a timeout at any point from the time specified above to
the time it would return from a steady-clock relative timeout on the difference between Ct and the time point of the call to the _until function[.](#timing-4.sentence-6)
*Recommended practice*: Implementations
should decrease the duration of the wait when the clock is adjusted forwards[.](#timing-4.sentence-7)
[5](#timing-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L146)
[*Note [2](#timing-note-2)*:
If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these
timeouts can fail to provide useful functionality[.](#timing-5.sentence-1)
— *end note*]
[6](#timing-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L152)
The resolution of timing provided by an implementation depends on both operating system
and hardware[.](#timing-6.sentence-1)
The finest resolution provided by an implementation is called the[*native resolution*](#def:native_resolution)[.](#timing-6.sentence-2)
[7](#timing-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L157)
Implementation-provided clocks that are used for these functions meet the[*Cpp17TrivialClock*](time.clock.req#:Cpp17TrivialClock "30.3Cpp17Clock requirements[time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3Cpp17Clock requirements"))[.](#timing-7.sentence-1)
[8](#timing-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L161)
A function that takes an argument which specifies a timeout will throw if,
during its execution, a clock, time point, or time duration throws an exception[.](#timing-8.sentence-1)
Such exceptions are referred to as [*timeout-related exceptions*](#def:timeout-related_exceptions)[.](#timing-8.sentence-2)
[*Note [3](#timing-note-3)*:
Instantiations of clock, time point and duration types supplied by
the implementation as specified in [[time.clock]](time.clock "30.7Clocks") do not throw exceptions[.](#timing-8.sentence-3)
— *end note*]
[293)](#footnote-293)[293)](#footnoteref-293)
Implementations for which standard time units are meaningful will typically
have a steady clock within their hardware implementation[.](#footnote-293.sentence-1)
### [32.2.5](#lockable) Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable)
#### [32.2.5.1](#lockable.general) General [[thread.req.lockable.general]](thread.req.lockable.general)
[1](#lockable.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L174)
An [*execution agent*](#def:execution_agent "32.2.5.1General[thread.req.lockable.general]") is an entity such as a thread that may perform work in parallel with
other execution agents[.](#lockable.general-1.sentence-1)
[*Note [1](#lockable.general-note-1)*:
Implementations or users can introduce other kinds of
agents such as processes or thread-pool tasks[.](#lockable.general-1.sentence-2)
— *end note*]
The calling agent is determined by
context, e.g., the calling thread that contains the call, and so on[.](#lockable.general-1.sentence-3)
[2](#lockable.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L184)
[*Note [2](#lockable.general-note-2)*:
Some lockable objects are “agent oblivious” in that they work for any
execution agent model because they do not determine or store the agent's ID (e.g., an
ordinary spin lock)[.](#lockable.general-2.sentence-1)
— *end note*]
[3](#lockable.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L191)
The standard library templates unique_lock ([[thread.lock.unique]](thread.lock.unique "32.6.5.4Class template unique_­lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5Class template shared_­lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3Class template scoped_­lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2Class template lock_­guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5Class condition_­variable_­any")) all operate on user-supplied
lockable objects[.](#lockable.general-3.sentence-1)
The [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements,
the [*Cpp17TimedLockable*](#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements,
the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the [*Cpp17SharedTimedLockable*](#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements
list the requirements imposed by these library types
in order to acquire or release ownership of a lock by a given execution agent[.](#lockable.general-3.sentence-2)
[*Note [3](#lockable.general-note-3)*:
The nature of any lock ownership and any synchronization it entails are not part
of these requirements[.](#lockable.general-3.sentence-3)
— *end note*]
[4](#lockable.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L209)
A lock on an object m is said to be
- [(4.1)](#lockable.general-4.1)
a [*non-shared lock*](#def:lock,non-shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock,try_lock,try_lock_for, ortry_lock_until on m, or
- [(4.2)](#lockable.general-4.2)
a [*shared lock*](#def:lock,shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock_shared,try_lock_shared,try_lock_shared_for, ortry_lock_shared_until on m[.](#lockable.general-4.sentence-1)
[*Note [4](#lockable.general-note-4)*:
Only the method of lock acquisition is considered;
the nature of any lock ownership is not part of these definitions[.](#lockable.general-4.sentence-2)
— *end note*]
#### [32.2.5.2](#lockable.basic) *Cpp17BasicLockable* requirements [[thread.req.lockable.basic]](thread.req.lockable.basic)
[1](#lockable.basic-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L232)
A type L meets the *Cpp17BasicLockable* requirements if the following expressions are
well-formed and have the specified semantics (m denotes a value of type L)[.](#lockable.basic-1.sentence-1)
[🔗](#lockable.basic-itemdecl:1)
`m.lock()
`
[2](#lockable.basic-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L241)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#lockable.basic-2.sentence-1)
If an exception
is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.basic-2.sentence-2)
[🔗](#lockable.basic-itemdecl:2)
`m.unlock()
`
[3](#lockable.basic-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L253)
*Preconditions*: The current execution agent holds a non-shared lock on m[.](#lockable.basic-3.sentence-1)
[4](#lockable.basic-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L257)
*Effects*: Releases a non-shared lock on m held by the current execution agent[.](#lockable.basic-4.sentence-1)
[5](#lockable.basic-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L261)
*Throws*: Nothing[.](#lockable.basic-5.sentence-1)
#### [32.2.5.3](#lockable.req) *Cpp17Lockable* requirements [[thread.req.lockable.req]](thread.req.lockable.req)
[1](#lockable.req-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L268)
A type L meets the *Cpp17Lockable* requirements if it meets the [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L)[.](#lockable.req-1.sentence-1)
[🔗](#lockable.req-itemdecl:1)
`m.try_lock()
`
[2](#lockable.req-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L278)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#lockable.req-2.sentence-1)
If an
exception is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.req-2.sentence-2)
[3](#lockable.req-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L283)
*Return type*: bool[.](#lockable.req-3.sentence-1)
[4](#lockable.req-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L286)
*Returns*: true if the lock was acquired, otherwise false[.](#lockable.req-4.sentence-1)
#### [32.2.5.4](#lockable.timed) *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]](thread.req.lockable.timed)
[1](#lockable.timed-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L293)
A type L meets the *Cpp17TimedLockable* requirements if it meets the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L, rel_time denotes a value of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes a value
of an instantiation of [time_point](time.point "30.6Class template time_­point[time.point]"))[.](#lockable.timed-1.sentence-1)
[🔗](#lockable.timed-itemdecl:1)
`m.try_lock_for(rel_time)
`
[2](#lockable.timed-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L305)
*Effects*: Attempts to acquire a lock for the current execution agent within the relative
timeout ([[thread.req.timing]](#timing "32.2.4Timing specifications")) specified by rel_time[.](#lockable.timed-2.sentence-1)
The function will not return
within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#lockable.timed-2.sentence-2)
If an exception is thrown then a lock has not been
acquired for the current execution agent[.](#lockable.timed-2.sentence-3)
[3](#lockable.timed-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L313)
*Return type*: bool[.](#lockable.timed-3.sentence-1)
[4](#lockable.timed-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L316)
*Returns*: true if the lock was acquired, otherwise false[.](#lockable.timed-4.sentence-1)
[🔗](#lockable.timed-itemdecl:2)
`m.try_lock_until(abs_time)
`
[5](#lockable.timed-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L326)
*Effects*: Attempts to acquire a lock for the current execution agent before the absolute
timeout ([[thread.req.timing]](#timing "32.2.4Timing specifications")) specified by abs_time[.](#lockable.timed-5.sentence-1)
The function will not return
before the timeout specified by abs_time unless it has obtained a lock on m for
the current execution agent[.](#lockable.timed-5.sentence-2)
If an exception is thrown then a lock has not been acquired
for the current execution agent[.](#lockable.timed-5.sentence-3)
[6](#lockable.timed-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L334)
*Return type*: bool[.](#lockable.timed-6.sentence-1)
[7](#lockable.timed-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L337)
*Returns*: true if the lock was acquired, otherwise false[.](#lockable.timed-7.sentence-1)
#### [32.2.5.5](#lockable.shared) *Cpp17SharedLockable* requirements [[thread.req.lockable.shared]](thread.req.lockable.shared)
[1](#lockable.shared-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L344)
A type L meets the *Cpp17SharedLockable* requirements if
the following expressions are well-formed, have the specified semantics, and
the expression m.try_lock_shared() has type bool (m denotes a value of type L):
[🔗](#lockable.shared-itemdecl:1)
`m.lock_shared()
`
[2](#lockable.shared-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L355)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#lockable.shared-2.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#lockable.shared-2.sentence-2)
[🔗](#lockable.shared-itemdecl:2)
`m.try_lock_shared()
`
[3](#lockable.shared-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L367)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#lockable.shared-3.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#lockable.shared-3.sentence-2)
[4](#lockable.shared-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L373)
*Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared-4.sentence-1)
[🔗](#lockable.shared-itemdecl:3)
`m.unlock_shared()
`
[5](#lockable.shared-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L383)
*Preconditions*: The current execution agent holds a shared lock on m[.](#lockable.shared-5.sentence-1)
[6](#lockable.shared-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L387)
*Effects*: Releases a shared lock on m held by the current execution agent[.](#lockable.shared-6.sentence-1)
[7](#lockable.shared-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L391)
*Throws*: Nothing[.](#lockable.shared-7.sentence-1)
#### [32.2.5.6](#lockable.shared.timed) *Cpp17SharedTimedLockable* requirements [[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed)
[1](#lockable.shared.timed-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L398)
A type L meets the *Cpp17SharedTimedLockable* requirements if
it meets the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the following expressions are well-formed, have type bool, and
have the specified semantics
(m denotes a value of type L,rel_time denotes a value of a specialization of chrono::duration, andabs_time denotes a value of a specialization of chrono::time_point)[.](#lockable.shared.timed-1.sentence-1)
[🔗](#lockable.shared.timed-itemdecl:1)
`m.try_lock_shared_for(rel_time)
`
[2](#lockable.shared.timed-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L412)
*Effects*: Attempts to acquire a lock for the current execution agent within
the relative timeout ([[thread.req.timing]](#timing "32.2.4Timing specifications")) specified by rel_time[.](#lockable.shared.timed-2.sentence-1)
The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#lockable.shared.timed-2.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#lockable.shared.timed-2.sentence-3)
[3](#lockable.shared.timed-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L421)
*Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared.timed-3.sentence-1)
[🔗](#lockable.shared.timed-itemdecl:2)
`m.try_lock_shared_until(abs_time)
`
[4](#lockable.shared.timed-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L431)
*Effects*: Attempts to acquire a lock for the current execution agent before
the absolute timeout ([[thread.req.timing]](#timing "32.2.4Timing specifications")) specified by abs_time[.](#lockable.shared.timed-4.sentence-1)
The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent[.](#lockable.shared.timed-4.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#lockable.shared.timed-4.sentence-3)
[5](#lockable.shared.timed-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L440)
*Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared.timed-5.sentence-1)

View File

@@ -0,0 +1,45 @@
[thread.req.exception]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#exception)
### 32.2.2 Exceptions [thread.req.exception]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L49)
Some functions described in this Clause are specified to throw exceptions of typesystem_error ([[syserr.syserr]](syserr.syserr "19.5.8Class system_­error"))[.](#1.sentence-1)
Such exceptions are thrown if
any of the function's error conditions is detected or
a call to
an operating system or other underlying API results in an error that prevents the
library function from
meeting its specifications[.](#1.sentence-2)
Failure to allocate storage is reported as described
in [[res.on.exception.handling]](res.on.exception.handling "16.4.6.14Restrictions on exception handling")[.](#1.sentence-3)
[*Example [1](#example-1)*:
Consider a function in this Clause that is specified to throw exceptions of typesystem_error and specifies error conditions that includeoperation_not_permitted for a thread that does not have the privilege to
perform the operation[.](#1.sentence-4)
Assume that, during the execution of this function, an errno of EPERM is reported by a POSIX API call used by the implementation[.](#1.sentence-5)
Since POSIX
specifies an errno of EPERM when “the caller does not have the privilege
to perform the operation”, the implementation maps EPERM to anerror_condition of operation_not_permitted ([[syserr]](syserr "19.5System error support")) and an exception
of type system_error is thrown[.](#1.sentence-6)
— *end example*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L71)
The error_code reported by such an exception's code() member function
compares equal to one of the conditions specified in the function's error condition
element[.](#2.sentence-1)

View File

@@ -0,0 +1,358 @@
[thread.req.lockable]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable)
### 32.2.5 Requirements for *Cpp17Lockable* types [thread.req.lockable]
#### [32.2.5.1](#general) General [[thread.req.lockable.general]](thread.req.lockable.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L174)
An [*execution agent*](#def:execution_agent "32.2.5.1General[thread.req.lockable.general]") is an entity such as a thread that may perform work in parallel with
other execution agents[.](#general-1.sentence-1)
[*Note [1](#general-note-1)*:
Implementations or users can introduce other kinds of
agents such as processes or thread-pool tasks[.](#general-1.sentence-2)
— *end note*]
The calling agent is determined by
context, e.g., the calling thread that contains the call, and so on[.](#general-1.sentence-3)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L184)
[*Note [2](#general-note-2)*:
Some lockable objects are “agent oblivious” in that they work for any
execution agent model because they do not determine or store the agent's ID (e.g., an
ordinary spin lock)[.](#general-2.sentence-1)
— *end note*]
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L191)
The standard library templates unique_lock ([[thread.lock.unique]](thread.lock.unique "32.6.5.4Class template unique_­lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5Class template shared_­lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3Class template scoped_­lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2Class template lock_­guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5Class condition_­variable_­any")) all operate on user-supplied
lockable objects[.](#general-3.sentence-1)
The [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements,
the [*Cpp17TimedLockable*](#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements,
the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the [*Cpp17SharedTimedLockable*](#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements
list the requirements imposed by these library types
in order to acquire or release ownership of a lock by a given execution agent[.](#general-3.sentence-2)
[*Note [3](#general-note-3)*:
The nature of any lock ownership and any synchronization it entails are not part
of these requirements[.](#general-3.sentence-3)
— *end note*]
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L209)
A lock on an object m is said to be
- [(4.1)](#general-4.1)
a [*non-shared lock*](#def:lock,non-shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock,try_lock,try_lock_for, ortry_lock_until on m, or
- [(4.2)](#general-4.2)
a [*shared lock*](#def:lock,shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock_shared,try_lock_shared,try_lock_shared_for, ortry_lock_shared_until on m[.](#general-4.sentence-1)
[*Note [4](#general-note-4)*:
Only the method of lock acquisition is considered;
the nature of any lock ownership is not part of these definitions[.](#general-4.sentence-2)
— *end note*]
#### [32.2.5.2](#basic) *Cpp17BasicLockable* requirements [[thread.req.lockable.basic]](thread.req.lockable.basic)
[1](#basic-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L232)
A type L meets the *Cpp17BasicLockable* requirements if the following expressions are
well-formed and have the specified semantics (m denotes a value of type L)[.](#basic-1.sentence-1)
[🔗](#basic-itemdecl:1)
`m.lock()
`
[2](#basic-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L241)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#basic-2.sentence-1)
If an exception
is thrown then a lock shall not have been acquired for the current execution agent[.](#basic-2.sentence-2)
[🔗](#basic-itemdecl:2)
`m.unlock()
`
[3](#basic-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L253)
*Preconditions*: The current execution agent holds a non-shared lock on m[.](#basic-3.sentence-1)
[4](#basic-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L257)
*Effects*: Releases a non-shared lock on m held by the current execution agent[.](#basic-4.sentence-1)
[5](#basic-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L261)
*Throws*: Nothing[.](#basic-5.sentence-1)
#### [32.2.5.3](#req) *Cpp17Lockable* requirements [[thread.req.lockable.req]](thread.req.lockable.req)
[1](#req-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L268)
A type L meets the *Cpp17Lockable* requirements if it meets the [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L)[.](#req-1.sentence-1)
[🔗](#req-itemdecl:1)
`m.try_lock()
`
[2](#req-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L278)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#req-2.sentence-1)
If an
exception is thrown then a lock shall not have been acquired for the current execution agent[.](#req-2.sentence-2)
[3](#req-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L283)
*Return type*: bool[.](#req-3.sentence-1)
[4](#req-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L286)
*Returns*: true if the lock was acquired, otherwise false[.](#req-4.sentence-1)
#### [32.2.5.4](#timed) *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]](thread.req.lockable.timed)
[1](#timed-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L293)
A type L meets the *Cpp17TimedLockable* requirements if it meets the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L, rel_time denotes a value of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes a value
of an instantiation of [time_point](time.point "30.6Class template time_­point[time.point]"))[.](#timed-1.sentence-1)
[🔗](#timed-itemdecl:1)
`m.try_lock_for(rel_time)
`
[2](#timed-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L305)
*Effects*: Attempts to acquire a lock for the current execution agent within the relative
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#timed-2.sentence-1)
The function will not return
within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#timed-2.sentence-2)
If an exception is thrown then a lock has not been
acquired for the current execution agent[.](#timed-2.sentence-3)
[3](#timed-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L313)
*Return type*: bool[.](#timed-3.sentence-1)
[4](#timed-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L316)
*Returns*: true if the lock was acquired, otherwise false[.](#timed-4.sentence-1)
[🔗](#timed-itemdecl:2)
`m.try_lock_until(abs_time)
`
[5](#timed-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L326)
*Effects*: Attempts to acquire a lock for the current execution agent before the absolute
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by abs_time[.](#timed-5.sentence-1)
The function will not return
before the timeout specified by abs_time unless it has obtained a lock on m for
the current execution agent[.](#timed-5.sentence-2)
If an exception is thrown then a lock has not been acquired
for the current execution agent[.](#timed-5.sentence-3)
[6](#timed-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L334)
*Return type*: bool[.](#timed-6.sentence-1)
[7](#timed-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L337)
*Returns*: true if the lock was acquired, otherwise false[.](#timed-7.sentence-1)
#### [32.2.5.5](#shared) *Cpp17SharedLockable* requirements [[thread.req.lockable.shared]](thread.req.lockable.shared)
[1](#shared-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L344)
A type L meets the *Cpp17SharedLockable* requirements if
the following expressions are well-formed, have the specified semantics, and
the expression m.try_lock_shared() has type bool (m denotes a value of type L):
[🔗](#shared-itemdecl:1)
`m.lock_shared()
`
[2](#shared-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L355)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#shared-2.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#shared-2.sentence-2)
[🔗](#shared-itemdecl:2)
`m.try_lock_shared()
`
[3](#shared-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L367)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#shared-3.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#shared-3.sentence-2)
[4](#shared-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L373)
*Returns*: true if the lock was acquired, false otherwise[.](#shared-4.sentence-1)
[🔗](#shared-itemdecl:3)
`m.unlock_shared()
`
[5](#shared-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L383)
*Preconditions*: The current execution agent holds a shared lock on m[.](#shared-5.sentence-1)
[6](#shared-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L387)
*Effects*: Releases a shared lock on m held by the current execution agent[.](#shared-6.sentence-1)
[7](#shared-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L391)
*Throws*: Nothing[.](#shared-7.sentence-1)
#### [32.2.5.6](#shared.timed) *Cpp17SharedTimedLockable* requirements [[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed)
[1](#shared.timed-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L398)
A type L meets the *Cpp17SharedTimedLockable* requirements if
it meets the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the following expressions are well-formed, have type bool, and
have the specified semantics
(m denotes a value of type L,rel_time denotes a value of a specialization of chrono::duration, andabs_time denotes a value of a specialization of chrono::time_point)[.](#shared.timed-1.sentence-1)
[🔗](#shared.timed-itemdecl:1)
`m.try_lock_shared_for(rel_time)
`
[2](#shared.timed-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L412)
*Effects*: Attempts to acquire a lock for the current execution agent within
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#shared.timed-2.sentence-1)
The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#shared.timed-2.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#shared.timed-2.sentence-3)
[3](#shared.timed-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L421)
*Returns*: true if the lock was acquired, false otherwise[.](#shared.timed-3.sentence-1)
[🔗](#shared.timed-itemdecl:2)
`m.try_lock_shared_until(abs_time)
`
[4](#shared.timed-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L431)
*Effects*: Attempts to acquire a lock for the current execution agent before
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by abs_time[.](#shared.timed-4.sentence-1)
The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent[.](#shared.timed-4.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#shared.timed-4.sentence-3)
[5](#shared.timed-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L440)
*Returns*: true if the lock was acquired, false otherwise[.](#shared.timed-5.sentence-1)

View File

@@ -0,0 +1,53 @@
[thread.req.lockable.basic]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.basic)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#basic)
#### 32.2.5.2 *Cpp17BasicLockable* requirements [thread.req.lockable.basic]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L232)
A type L meets the *Cpp17BasicLockable* requirements if the following expressions are
well-formed and have the specified semantics (m denotes a value of type L)[.](#1.sentence-1)
[🔗](#itemdecl:1)
`m.lock()
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L241)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#2.sentence-1)
If an exception
is thrown then a lock shall not have been acquired for the current execution agent[.](#2.sentence-2)
[🔗](#itemdecl:2)
`m.unlock()
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L253)
*Preconditions*: The current execution agent holds a non-shared lock on m[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L257)
*Effects*: Releases a non-shared lock on m held by the current execution agent[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L261)
*Throws*: Nothing[.](#5.sentence-1)

View File

@@ -0,0 +1,80 @@
[thread.req.lockable.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.general)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#general)
#### 32.2.5.1 General [thread.req.lockable.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L174)
An [*execution agent*](#def:execution_agent "32.2.5.1General[thread.req.lockable.general]") is an entity such as a thread that may perform work in parallel with
other execution agents[.](#1.sentence-1)
[*Note [1](#note-1)*:
Implementations or users can introduce other kinds of
agents such as processes or thread-pool tasks[.](#1.sentence-2)
— *end note*]
The calling agent is determined by
context, e.g., the calling thread that contains the call, and so on[.](#1.sentence-3)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L184)
[*Note [2](#note-2)*:
Some lockable objects are “agent oblivious” in that they work for any
execution agent model because they do not determine or store the agent's ID (e.g., an
ordinary spin lock)[.](#2.sentence-1)
— *end note*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L191)
The standard library templates unique_lock ([[thread.lock.unique]](thread.lock.unique "32.6.5.4Class template unique_­lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5Class template shared_­lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3Class template scoped_­lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2Class template lock_­guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5Class condition_­variable_­any")) all operate on user-supplied
lockable objects[.](#3.sentence-1)
The [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements,
the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements,
the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements
list the requirements imposed by these library types
in order to acquire or release ownership of a lock by a given execution agent[.](#3.sentence-2)
[*Note [3](#note-3)*:
The nature of any lock ownership and any synchronization it entails are not part
of these requirements[.](#3.sentence-3)
— *end note*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L209)
A lock on an object m is said to be
- [(4.1)](#4.1)
a [*non-shared lock*](#def:lock,non-shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock,try_lock,try_lock_for, ortry_lock_until on m, or
- [(4.2)](#4.2)
a [*shared lock*](#def:lock,shared "32.2.5.1General[thread.req.lockable.general]") if it is acquired by a call tolock_shared,try_lock_shared,try_lock_shared_for, ortry_lock_shared_until on m[.](#4.sentence-1)
[*Note [4](#note-4)*:
Only the method of lock acquisition is considered;
the nature of any lock ownership is not part of these definitions[.](#4.sentence-2)
— *end note*]

View File

@@ -0,0 +1,42 @@
[thread.req.lockable.req]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.req)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#req)
#### 32.2.5.3 *Cpp17Lockable* requirements [thread.req.lockable.req]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L268)
A type L meets the *Cpp17Lockable* requirements if it meets the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L)[.](#1.sentence-1)
[🔗](#itemdecl:1)
`m.try_lock()
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L278)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#2.sentence-1)
If an
exception is thrown then a lock shall not have been acquired for the current execution agent[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L283)
*Return type*: bool[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L286)
*Returns*: true if the lock was acquired, otherwise false[.](#4.sentence-1)

View File

@@ -0,0 +1,74 @@
[thread.req.lockable.shared]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.shared)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#shared)
#### 32.2.5.5 *Cpp17SharedLockable* requirements [thread.req.lockable.shared]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L344)
A type L meets the *Cpp17SharedLockable* requirements if
the following expressions are well-formed, have the specified semantics, and
the expression m.try_lock_shared() has type bool (m denotes a value of type L):
[🔗](#itemdecl:1)
`m.lock_shared()
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L355)
*Effects*: Blocks until a lock can be acquired for the current execution agent[.](#2.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#2.sentence-2)
[🔗](#itemdecl:2)
`m.try_lock_shared()
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L367)
*Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#3.sentence-1)
If an exception is thrown then a lock shall not have been acquired for
the current execution agent[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L373)
*Returns*: true if the lock was acquired, false otherwise[.](#4.sentence-1)
[🔗](#itemdecl:3)
`m.unlock_shared()
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L383)
*Preconditions*: The current execution agent holds a shared lock on m[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L387)
*Effects*: Releases a shared lock on m held by the current execution agent[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L391)
*Throws*: Nothing[.](#7.sentence-1)

View File

@@ -0,0 +1,65 @@
[thread.req.lockable.shared.timed]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.shared.timed)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#shared.timed)
#### 32.2.5.6 *Cpp17SharedTimedLockable* requirements [thread.req.lockable.shared.timed]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L398)
A type L meets the *Cpp17SharedTimedLockable* requirements if
it meets the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements, and
the following expressions are well-formed, have type bool, and
have the specified semantics
(m denotes a value of type L,rel_time denotes a value of a specialization of chrono::duration, andabs_time denotes a value of a specialization of chrono::time_point)[.](#1.sentence-1)
[🔗](#itemdecl:1)
`m.try_lock_shared_for(rel_time)
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L412)
*Effects*: Attempts to acquire a lock for the current execution agent within
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#2.sentence-1)
The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#2.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#2.sentence-3)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L421)
*Returns*: true if the lock was acquired, false otherwise[.](#3.sentence-1)
[🔗](#itemdecl:2)
`m.try_lock_shared_until(abs_time)
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L431)
*Effects*: Attempts to acquire a lock for the current execution agent before
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by abs_time[.](#4.sentence-1)
The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent[.](#4.sentence-2)
If an exception is thrown then a lock has not been acquired for
the current execution agent[.](#4.sentence-3)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L440)
*Returns*: true if the lock was acquired, false otherwise[.](#5.sentence-1)

View File

@@ -0,0 +1,79 @@
[thread.req.lockable.timed]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#lockable.timed)
### 32.2.5 Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable#timed)
#### 32.2.5.4 *Cpp17TimedLockable* requirements [thread.req.lockable.timed]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L293)
A type L meets the *Cpp17TimedLockable* requirements if it meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements and the following expressions are well-formed and have the specified semantics
(m denotes a value of type L, rel_time denotes a value of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes a value
of an instantiation of [time_point](time.point "30.6Class template time_­point[time.point]"))[.](#1.sentence-1)
[🔗](#itemdecl:1)
`m.try_lock_for(rel_time)
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L305)
*Effects*: Attempts to acquire a lock for the current execution agent within the relative
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#2.sentence-1)
The function will not return
within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#2.sentence-2)
If an exception is thrown then a lock has not been
acquired for the current execution agent[.](#2.sentence-3)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L313)
*Return type*: bool[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L316)
*Returns*: true if the lock was acquired, otherwise false[.](#4.sentence-1)
[🔗](#itemdecl:2)
`m.try_lock_until(abs_time)
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L326)
*Effects*: Attempts to acquire a lock for the current execution agent before the absolute
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by abs_time[.](#5.sentence-1)
The function will not return
before the timeout specified by abs_time unless it has obtained a lock on m for
the current execution agent[.](#5.sentence-2)
If an exception is thrown then a lock has not been acquired
for the current execution agent[.](#5.sentence-3)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L334)
*Return type*: bool[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L337)
*Returns*: true if the lock was acquired, otherwise false[.](#7.sentence-1)

View File

@@ -0,0 +1,27 @@
[thread.req.native]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#native)
### 32.2.3 Native handles [thread.req.native]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L78)
Several classes described in this Clause have members native_handle_type andnative_handle[.](#1.sentence-1)
The presence of these members and their semantics isimplementation-defined[.](#1.sentence-2)
[*Note [1](#note-1)*:
These members allow implementations to provide access
to implementation details[.](#1.sentence-3)
Their names are specified to facilitate portable compile-time
detection[.](#1.sentence-4)
Actual use of these members is inherently non-portable[.](#1.sentence-5)
— *end note*]

View File

@@ -0,0 +1,28 @@
[thread.req.paramname]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#paramname)
### 32.2.1 Template parameter names [thread.req.paramname]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L31)
Throughout this Clause, the names of template parameters are used to express type
requirements[.](#1.sentence-1)
Predicate is a function object type ([[function.objects]](function.objects "22.10Function objects"))[.](#1.sentence-2)
Let pred denote an lvalue of type Predicate[.](#1.sentence-3)
Then the expression pred() shall be well-formed and
the type decltype(pred()) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2Boolean testability"))[.](#1.sentence-4)
The return value of pred(), converted to bool,
yields true if the corresponding test condition is satisfied, andfalse otherwise[.](#1.sentence-5)
If a template parameter is named Clock,
the corresponding template argument shall be a type C that meets the [*Cpp17Clock*](time.clock.req#:Cpp17Clock "30.3Cpp17Clock requirements[time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3Cpp17Clock requirements"));
the program is ill-formed if is_clock_v<C> is false[.](#1.sentence-6)

View File

@@ -0,0 +1,138 @@
[thread.req.timing]
# 32 Concurrency support library [[thread]](./#thread)
## 32.2 Requirements [[thread.req]](thread.req#timing)
### 32.2.4 Timing specifications [thread.req.timing]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L90)
Several functions described in this Clause take an argument to specify a timeout[.](#1.sentence-1)
These
timeouts are specified as either a duration or a time_point type as
specified in [[time]](time "30Time library")[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L95)
Implementations necessarily have some delay in returning from a timeout[.](#2.sentence-1)
Any overhead in
interrupt response, function return, and scheduling induces a “quality of implementation”
delay, expressed as duration Di[.](#2.sentence-2)
Ideally, this delay would be zero[.](#2.sentence-3)
Further, any contention for
processor and memory resources induces a “quality of management” delay, expressed as durationDm[.](#2.sentence-4)
The delay durations may vary from timeout to timeout, but in all cases shorter is better[.](#2.sentence-5)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L102)
The functions whose names end in _for take an argument that
specifies a duration[.](#3.sentence-1)
These functions produce relative timeouts[.](#3.sentence-2)
Implementations
should use a steady clock to measure time for these functions[.](#3.sentence-3)[293](#footnote-293 "Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation.")
Given a duration
argument Dt, the real-time duration of the timeout is Dt+Di+Dm[.](#3.sentence-4)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L113)
The functions whose names end in _until take an argument that specifies a time
point[.](#4.sentence-1)
These functions produce absolute timeouts[.](#4.sentence-2)
Implementations should use the clock
specified in the time point to measure time for these functions[.](#4.sentence-3)
Given a clock time point
argument Ct, the clock time point of the return from timeout should be Ct+Di+Dm when the clock is not adjusted during the timeout[.](#4.sentence-4)
If the clock is adjusted to the time Ca during the timeout, the behavior should be as follows:
- [(4.1)](#4.1)
If Ca>Ct, the waiting function should wake as soon as possible, i.e., Ca+Di+Dm,
since the timeout is already satisfied[.](#4.1.sentence-1)
This specification may result in the total
duration of the wait decreasing when measured against a steady clock[.](#4.1.sentence-2)
- [(4.2)](#4.2)
If Ca≤Ct, the waiting function should not time out until Clock::now() returns a
time Cn≥Ct, i.e., waking at Ct+Di+Dm[.](#4.2.sentence-1)
[*Note [1](#note-1)*:
When the clock is adjusted
backwards, this specification can result in the total duration of the wait increasing when
measured against a steady clock[.](#4.2.sentence-2)
When the clock is adjusted forwards, this specification can
result in the total duration of the wait decreasing when measured against a steady clock[.](#4.2.sentence-3)
— *end note*]
An implementation returns from such a timeout at any point from the time specified above to
the time it would return from a steady-clock relative timeout on the difference between Ct and the time point of the call to the _until function[.](#4.sentence-6)
*Recommended practice*: Implementations
should decrease the duration of the wait when the clock is adjusted forwards[.](#4.sentence-7)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L146)
[*Note [2](#note-2)*:
If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these
timeouts can fail to provide useful functionality[.](#5.sentence-1)
— *end note*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L152)
The resolution of timing provided by an implementation depends on both operating system
and hardware[.](#6.sentence-1)
The finest resolution provided by an implementation is called the[*native resolution*](#def:native_resolution)[.](#6.sentence-2)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L157)
Implementation-provided clocks that are used for these functions meet the[*Cpp17TrivialClock*](time.clock.req#:Cpp17TrivialClock "30.3Cpp17Clock requirements[time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3Cpp17Clock requirements"))[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L161)
A function that takes an argument which specifies a timeout will throw if,
during its execution, a clock, time point, or time duration throws an exception[.](#8.sentence-1)
Such exceptions are referred to as [*timeout-related exceptions*](#def:timeout-related_exceptions)[.](#8.sentence-2)
[*Note [3](#note-3)*:
Instantiations of clock, time point and duration types supplied by
the implementation as specified in [[time.clock]](time.clock "30.7Clocks") do not throw exceptions[.](#8.sentence-3)
— *end note*]
[293)](#footnote-293)[293)](#footnoteref-293)
Implementations for which standard time units are meaningful will typically
have a steady clock within their hardware implementation[.](#footnote-293.sentence-1)

251
cppdraft/thread/sema.md Normal file
View File

@@ -0,0 +1,251 @@
[thread.sema]
# 32 Concurrency support library [[thread]](./#thread)
## 32.8 Semaphore [thread.sema]
### [32.8.1](#general) General [[thread.sema.general]](thread.sema.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10435)
Semaphores are lightweight synchronization primitives
used to constrain concurrent access to a shared resource[.](#general-1.sentence-1)
They are widely used to implement other synchronization primitives and,
whenever both are applicable, can be more efficient than condition variables[.](#general-1.sentence-2)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10441)
A counting semaphore is a semaphore object
that models a non-negative resource count[.](#general-2.sentence-1)
A binary semaphore is a semaphore object that has only two states[.](#general-2.sentence-2)
A binary semaphore should be more efficient than
the default implementation of a counting semaphore with a unit resource count[.](#general-2.sentence-3)
### [32.8.2](#semaphore.syn) Header <semaphore> synopsis [[semaphore.syn]](semaphore.syn)
[🔗](#header:%3csemaphore%3e)
namespace std {// [[thread.sema.cnt]](#cnt "32.8.3Class template counting_­semaphore"), class template counting_semaphoretemplate<ptrdiff_t least_max_value = *implementation-defined*>class counting_semaphore; using [binary_semaphore](#lib:binary_semaphore "32.8.2Header <semaphore> synopsis[semaphore.syn]") = counting_semaphore<1>;}
### [32.8.3](#cnt) Class template counting_semaphore [[thread.sema.cnt]](thread.sema.cnt)
namespace std {template<ptrdiff_t least_max_value = *implementation-defined*>class counting_semaphore {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit counting_semaphore(ptrdiff_t desired); ~counting_semaphore();
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete; void release(ptrdiff_t update = 1); void acquire(); bool try_acquire() noexcept; template<class Rep, class Period>bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time); private: ptrdiff_t counter; // *exposition only*};}
[1](#cnt-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10490)
Class template counting_semaphore maintains an internal counter
that is initialized when the semaphore is created[.](#cnt-1.sentence-1)
The counter is decremented when a thread acquires the semaphore, and
is incremented when a thread releases the semaphore[.](#cnt-1.sentence-2)
If a thread tries to acquire the semaphore when the counter is zero,
the thread will block
until another thread increments the counter by releasing the semaphore[.](#cnt-1.sentence-3)
[2](#cnt-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10500)
least_max_value shall be non-negative; otherwise the program is ill-formed[.](#cnt-2.sentence-1)
[3](#cnt-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10503)
Concurrent invocations of the member functions of counting_semaphore,
other than its destructor, do not introduce data races[.](#cnt-3.sentence-1)
[🔗](#lib:max,counting_semaphore)
`static constexpr ptrdiff_t max() noexcept;
`
[4](#cnt-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10513)
*Returns*: The maximum value of counter[.](#cnt-4.sentence-1)
This value is greater than or equal to least_max_value[.](#cnt-4.sentence-2)
[🔗](#lib:counting_semaphore,constructor)
`constexpr explicit counting_semaphore(ptrdiff_t desired);
`
[5](#cnt-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10525)
*Preconditions*: desired >= 0 is true, anddesired <= max() is true[.](#cnt-5.sentence-1)
[6](#cnt-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10530)
*Effects*: Initializes counter with desired[.](#cnt-6.sentence-1)
[7](#cnt-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10534)
*Throws*: Nothing[.](#cnt-7.sentence-1)
[🔗](#lib:release,counting_semaphore)
`void release(ptrdiff_t update = 1);
`
[8](#cnt-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10545)
*Preconditions*: update >= 0 is true, andupdate <= max() - counter is true[.](#cnt-8.sentence-1)
[9](#cnt-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10550)
*Effects*: Atomically execute counter += update[.](#cnt-9.sentence-1)
Then, unblocks any threads
that are waiting for counter to be greater than zero[.](#cnt-9.sentence-2)
[10](#cnt-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10556)
*Synchronization*: Strongly happens before invocations of try_acquire that observe the result of the effects[.](#cnt-10.sentence-1)
[11](#cnt-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10561)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#cnt-11.sentence-1)
[12](#cnt-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10565)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#cnt-12.sentence-1)
[🔗](#lib:try_acquire,counting_semaphore)
`bool try_acquire() noexcept;
`
[13](#cnt-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10577)
*Effects*: Attempts to atomically decrement counter if it is positive,
without blocking[.](#cnt-13.sentence-1)
If counter is not decremented, there is no effect andtry_acquire immediately returns[.](#cnt-13.sentence-2)
An implementation may fail to decrement counter even if it is positive[.](#cnt-13.sentence-3)
[*Note [1](#cnt-note-1)*:
This spurious failure is normally uncommon, but
allows interesting implementations
based on a simple compare and exchange ([[atomics]](atomics "32.5Atomic operations"))[.](#cnt-13.sentence-4)
— *end note*]
An implementation should ensure that try_acquire does not consistently return false in the absence of contending semaphore operations[.](#cnt-13.sentence-5)
[14](#cnt-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10594)
*Returns*: true if counter was decremented, otherwise false[.](#cnt-14.sentence-1)
[🔗](#lib:acquire,counting_semaphore)
`void acquire();
`
[15](#cnt-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10605)
*Effects*: Repeatedly performs the following steps, in order:
- [(15.1)](#cnt-15.1)
Evaluates try_acquire()[.](#cnt-15.1.sentence-1)
If the result is true, returns[.](#cnt-15.1.sentence-2)
- [(15.2)](#cnt-15.2)
Blocks on *this until counter is greater than zero[.](#cnt-15.2.sentence-1)
[16](#cnt-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10615)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#cnt-16.sentence-1)
[17](#cnt-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10619)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#cnt-17.sentence-1)
[🔗](#lib:try_acquire_for,counting_semaphore)
`template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[18](#cnt-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10635)
*Effects*: Repeatedly performs the following steps, in order:
- [(18.1)](#cnt-18.1)
Evaluates try_acquire()[.](#cnt-18.1.sentence-1)
If the result is true, returns true[.](#cnt-18.1.sentence-2)
- [(18.2)](#cnt-18.2)
Blocks on *this until counter is greater than zero or until the timeout expires[.](#cnt-18.2.sentence-1)
If it is unblocked by the timeout expiring, returns false[.](#cnt-18.2.sentence-2)
The timeout expires ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
when the current time is after abs_time (for try_acquire_until)
or when at least rel_time has passed
from the start of the function (for try_acquire_for)[.](#cnt-18.sentence-2)
[19](#cnt-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10653)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#cnt-19.sentence-1)
[20](#cnt-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10658)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#cnt-20.sentence-1)

221
cppdraft/thread/sema/cnt.md Normal file
View File

@@ -0,0 +1,221 @@
[thread.sema.cnt]
# 32 Concurrency support library [[thread]](./#thread)
## 32.8 Semaphore [[thread.sema]](thread.sema#cnt)
### 32.8.3 Class template counting_semaphore [thread.sema.cnt]
namespace std {template<ptrdiff_t least_max_value = *implementation-defined*>class counting_semaphore {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit counting_semaphore(ptrdiff_t desired); ~counting_semaphore();
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete; void release(ptrdiff_t update = 1); void acquire(); bool try_acquire() noexcept; template<class Rep, class Period>bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time); private: ptrdiff_t counter; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10490)
Class template counting_semaphore maintains an internal counter
that is initialized when the semaphore is created[.](#1.sentence-1)
The counter is decremented when a thread acquires the semaphore, and
is incremented when a thread releases the semaphore[.](#1.sentence-2)
If a thread tries to acquire the semaphore when the counter is zero,
the thread will block
until another thread increments the counter by releasing the semaphore[.](#1.sentence-3)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10500)
least_max_value shall be non-negative; otherwise the program is ill-formed[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10503)
Concurrent invocations of the member functions of counting_semaphore,
other than its destructor, do not introduce data races[.](#3.sentence-1)
[🔗](#lib:max,counting_semaphore)
`static constexpr ptrdiff_t max() noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10513)
*Returns*: The maximum value of counter[.](#4.sentence-1)
This value is greater than or equal to least_max_value[.](#4.sentence-2)
[🔗](#lib:counting_semaphore,constructor)
`constexpr explicit counting_semaphore(ptrdiff_t desired);
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10525)
*Preconditions*: desired >= 0 is true, anddesired <= max() is true[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10530)
*Effects*: Initializes counter with desired[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10534)
*Throws*: Nothing[.](#7.sentence-1)
[🔗](#lib:release,counting_semaphore)
`void release(ptrdiff_t update = 1);
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10545)
*Preconditions*: update >= 0 is true, andupdate <= max() - counter is true[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10550)
*Effects*: Atomically execute counter += update[.](#9.sentence-1)
Then, unblocks any threads
that are waiting for counter to be greater than zero[.](#9.sentence-2)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10556)
*Synchronization*: Strongly happens before invocations of try_acquire that observe the result of the effects[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10561)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10565)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#12.sentence-1)
[🔗](#lib:try_acquire,counting_semaphore)
`bool try_acquire() noexcept;
`
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10577)
*Effects*: Attempts to atomically decrement counter if it is positive,
without blocking[.](#13.sentence-1)
If counter is not decremented, there is no effect andtry_acquire immediately returns[.](#13.sentence-2)
An implementation may fail to decrement counter even if it is positive[.](#13.sentence-3)
[*Note [1](#note-1)*:
This spurious failure is normally uncommon, but
allows interesting implementations
based on a simple compare and exchange ([[atomics]](atomics "32.5Atomic operations"))[.](#13.sentence-4)
— *end note*]
An implementation should ensure that try_acquire does not consistently return false in the absence of contending semaphore operations[.](#13.sentence-5)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10594)
*Returns*: true if counter was decremented, otherwise false[.](#14.sentence-1)
[🔗](#lib:acquire,counting_semaphore)
`void acquire();
`
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10605)
*Effects*: Repeatedly performs the following steps, in order:
- [(15.1)](#15.1)
Evaluates try_acquire()[.](#15.1.sentence-1)
If the result is true, returns[.](#15.1.sentence-2)
- [(15.2)](#15.2)
Blocks on *this until counter is greater than zero[.](#15.2.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10615)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#16.sentence-1)
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10619)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#17.sentence-1)
[🔗](#lib:try_acquire_for,counting_semaphore)
`template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10635)
*Effects*: Repeatedly performs the following steps, in order:
- [(18.1)](#18.1)
Evaluates try_acquire()[.](#18.1.sentence-1)
If the result is true, returns true[.](#18.1.sentence-2)
- [(18.2)](#18.2)
Blocks on *this until counter is greater than zero or until the timeout expires[.](#18.2.sentence-1)
If it is unblocked by the timeout expiring, returns false[.](#18.2.sentence-2)
The timeout expires ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
when the current time is after abs_time (for try_acquire_until)
or when at least rel_time has passed
from the start of the function (for try_acquire_for)[.](#18.sentence-2)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10653)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#19.sentence-1)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10658)
*Error conditions*: Any of the error conditions
allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"))[.](#20.sentence-1)

View File

@@ -0,0 +1,29 @@
[thread.sema.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.8 Semaphore [[thread.sema]](thread.sema#general)
### 32.8.1 General [thread.sema.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10435)
Semaphores are lightweight synchronization primitives
used to constrain concurrent access to a shared resource[.](#1.sentence-1)
They are widely used to implement other synchronization primitives and,
whenever both are applicable, can be more efficient than condition variables[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10441)
A counting semaphore is a semaphore object
that models a non-negative resource count[.](#2.sentence-1)
A binary semaphore is a semaphore object that has only two states[.](#2.sentence-2)
A binary semaphore should be more efficient than
the default implementation of a counting semaphore with a unit resource count[.](#2.sentence-3)

View File

@@ -0,0 +1,58 @@
[thread.sharedmutex.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedmutex.class)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedmutex.class)
#### 32.6.4.4 Shared mutex types [[thread.sharedmutex.requirements]](thread.sharedmutex.requirements#thread.sharedmutex.class)
#### 32.6.4.4.2 Class shared_mutex [thread.sharedmutex.class]
[🔗](#lib:shared_mutex)
namespace std {class shared_mutex {public: shared_mutex(); ~shared_mutex();
shared_mutex(const shared_mutex&) = delete;
shared_mutex& operator=(const shared_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); void unlock_shared(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7963)
The class shared_mutex provides a non-recursive mutex
with shared ownership semantics[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7967)
The class shared_mutex meets
all of the shared mutex requirements ([[thread.sharedmutex.requirements]](thread.sharedmutex.requirements "32.6.4.4Shared mutex types"))[.](#2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7972)
The behavior of a program is undefined if
- [(3.1)](#3.1)
it destroys a shared_mutex object owned by any thread,
- [(3.2)](#3.2)
a thread attempts to recursively gain any ownership of a shared_mutex, or
- [(3.3)](#3.3)
a thread terminates while possessing any ownership of a shared_mutex[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7980)
shared_mutex may be a synonym for shared_timed_mutex[.](#4.sentence-1)

View File

@@ -0,0 +1,247 @@
[thread.sharedmutex.requirements]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedmutex.requirements)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedmutex.requirements)
#### 32.6.4.4 Shared mutex types [thread.sharedmutex.requirements]
#### [32.6.4.4.1](#general) General [[thread.sharedmutex.requirements.general]](thread.sharedmutex.requirements.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7815)
The standard library types shared_mutex and shared_timed_mutex are [*shared mutex types*](#def:shared_mutex_types "32.6.4.4.1General[thread.sharedmutex.requirements.general]")[.](#general-1.sentence-1)
Shared mutex types meet the requirements of
mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types")) and additionally
meet the requirements set out below[.](#general-1.sentence-2)
In this description,m denotes an object of a shared mutex type[.](#general-1.sentence-3)
[*Note [1](#general-note-1)*:
The shared mutex types meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#general-1.sentence-4)
— *end note*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7826)
In addition to the exclusive lock ownership mode specified
in [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1General[thread.sharedmutex.requirements.general]") ownership mode[.](#general-2.sentence-1)
Multiple execution agents can
simultaneously hold a shared lock ownership of a shared mutex type[.](#general-2.sentence-2)
But no
execution agent holds a shared lock while another execution agent holds an
exclusive lock on the same shared mutex type, and vice-versa[.](#general-2.sentence-3)
The maximum
number of execution agents which can share a shared lock on a single shared
mutex type is unspecified, but is at least 10000[.](#general-2.sentence-4)
If more than the
maximum number of execution agents attempt to obtain a shared lock, the
excess execution agents block until the number of shared locks are
reduced below the maximum amount by other execution agents releasing their
shared lock[.](#general-2.sentence-5)
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7841)
The expression m.lock_shared() is well-formed and has the
following semantics:
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7845)
*Preconditions*: The calling thread has no ownership of the mutex[.](#general-4.sentence-1)
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7849)
*Effects*: Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread[.](#general-5.sentence-1)
If an exception is thrown then a shared lock has not been acquired for the current thread[.](#general-5.sentence-2)
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7855)
*Synchronization*: Prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#general-6.sentence-1)
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7859)
*Postconditions*: The calling thread has a shared lock on the mutex[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7863)
*Return type*: void[.](#general-8.sentence-1)
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7866)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#general-9.sentence-1)
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7870)
*Error conditions*:
- [(10.1)](#general-10.1)
operation_not_permitted — if the thread does not have the privilege to perform the operation[.](#general-10.1.sentence-1)
- [(10.2)](#general-10.2)
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur[.](#general-10.2.sentence-1)
[11](#general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7878)
The expression m.unlock_shared() is well-formed and has the following semantics:
[12](#general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7881)
*Preconditions*: The calling thread holds a shared lock on the mutex[.](#general-12.sentence-1)
[13](#general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7885)
*Effects*: Releases a shared lock on the mutex held by the calling thread[.](#general-13.sentence-1)
[14](#general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7889)
*Return type*: void[.](#general-14.sentence-1)
[15](#general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7892)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequentlock() operations that obtain ownership on the same object[.](#general-15.sentence-1)
[16](#general-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7897)
*Throws*: Nothing[.](#general-16.sentence-1)
[17](#general-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7902)
The expression m.try_lock_shared() is well-formed and has the following semantics:
[18](#general-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7905)
*Preconditions*: The calling thread has no ownership of the mutex[.](#general-18.sentence-1)
[19](#general-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7909)
*Effects*: Attempts to obtain shared ownership of the mutex for the calling
thread without blocking[.](#general-19.sentence-1)
If shared ownership is not obtained, there is no
effect and try_lock_shared() immediately returns[.](#general-19.sentence-2)
An implementation
may fail to obtain the lock even if it is not held by any other thread[.](#general-19.sentence-3)
[20](#general-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7916)
*Synchronization*: If try_lock_shared() returns true, prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this
operation[.](#general-20.sentence-1)
[21](#general-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7922)
*Return type*: bool[.](#general-21.sentence-1)
[22](#general-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7925)
*Returns*: true if the shared lock was acquired, otherwise false[.](#general-22.sentence-1)
[23](#general-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7929)
*Throws*: Nothing[.](#general-23.sentence-1)
#### [32.6.4.4.2](#thread.sharedmutex.class) Class shared_mutex [[thread.sharedmutex.class]](thread.sharedmutex.class)
[🔗](#lib:shared_mutex)
namespace std {class shared_mutex {public: shared_mutex(); ~shared_mutex();
shared_mutex(const shared_mutex&) = delete;
shared_mutex& operator=(const shared_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); void unlock_shared(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.sharedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7963)
The class shared_mutex provides a non-recursive mutex
with shared ownership semantics[.](#thread.sharedmutex.class-1.sentence-1)
[2](#thread.sharedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7967)
The class shared_mutex meets
all of the shared mutex requirements ([thread.sharedmutex.requirements])[.](#thread.sharedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.sharedmutex.class-2.sentence-2)
[3](#thread.sharedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7972)
The behavior of a program is undefined if
- [(3.1)](#thread.sharedmutex.class-3.1)
it destroys a shared_mutex object owned by any thread,
- [(3.2)](#thread.sharedmutex.class-3.2)
a thread attempts to recursively gain any ownership of a shared_mutex, or
- [(3.3)](#thread.sharedmutex.class-3.3)
a thread terminates while possessing any ownership of a shared_mutex[.](#thread.sharedmutex.class-3.sentence-1)
[4](#thread.sharedmutex.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7980)
shared_mutex may be a synonym for shared_timed_mutex[.](#thread.sharedmutex.class-4.sentence-1)

View File

@@ -0,0 +1,198 @@
[thread.sharedmutex.requirements.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedmutex.requirements.general)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedmutex.requirements.general)
#### 32.6.4.4 Shared mutex types [[thread.sharedmutex.requirements]](thread.sharedmutex.requirements#general)
#### 32.6.4.4.1 General [thread.sharedmutex.requirements.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7815)
The standard library types shared_mutex and shared_timed_mutex are [*shared mutex types*](#def:shared_mutex_types "32.6.4.4.1General[thread.sharedmutex.requirements.general]")[.](#1.sentence-1)
Shared mutex types meet the requirements of
mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types")) and additionally
meet the requirements set out below[.](#1.sentence-2)
In this description,m denotes an object of a shared mutex type[.](#1.sentence-3)
[*Note [1](#note-1)*:
The shared mutex types meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#1.sentence-4)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7826)
In addition to the exclusive lock ownership mode specified
in [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1General[thread.sharedmutex.requirements.general]") ownership mode[.](#2.sentence-1)
Multiple execution agents can
simultaneously hold a shared lock ownership of a shared mutex type[.](#2.sentence-2)
But no
execution agent holds a shared lock while another execution agent holds an
exclusive lock on the same shared mutex type, and vice-versa[.](#2.sentence-3)
The maximum
number of execution agents which can share a shared lock on a single shared
mutex type is unspecified, but is at least 10000[.](#2.sentence-4)
If more than the
maximum number of execution agents attempt to obtain a shared lock, the
excess execution agents block until the number of shared locks are
reduced below the maximum amount by other execution agents releasing their
shared lock[.](#2.sentence-5)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7841)
The expression m.lock_shared() is well-formed and has the
following semantics:
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7845)
*Preconditions*: The calling thread has no ownership of the mutex[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7849)
*Effects*: Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread[.](#5.sentence-1)
If an exception is thrown then a shared lock has not been acquired for the current thread[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7855)
*Synchronization*: Prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7859)
*Postconditions*: The calling thread has a shared lock on the mutex[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7863)
*Return type*: void[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7866)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7870)
*Error conditions*:
- [(10.1)](#10.1)
operation_not_permitted — if the thread does not have the privilege to perform the operation[.](#10.1.sentence-1)
- [(10.2)](#10.2)
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur[.](#10.2.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7878)
The expression m.unlock_shared() is well-formed and has the following semantics:
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7881)
*Preconditions*: The calling thread holds a shared lock on the mutex[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7885)
*Effects*: Releases a shared lock on the mutex held by the calling thread[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7889)
*Return type*: void[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7892)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequentlock() operations that obtain ownership on the same object[.](#15.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7897)
*Throws*: Nothing[.](#16.sentence-1)
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7902)
The expression m.try_lock_shared() is well-formed and has the following semantics:
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7905)
*Preconditions*: The calling thread has no ownership of the mutex[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7909)
*Effects*: Attempts to obtain shared ownership of the mutex for the calling
thread without blocking[.](#19.sentence-1)
If shared ownership is not obtained, there is no
effect and try_lock_shared() immediately returns[.](#19.sentence-2)
An implementation
may fail to obtain the lock even if it is not held by any other thread[.](#19.sentence-3)
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7916)
*Synchronization*: If try_lock_shared() returns true, prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this
operation[.](#20.sentence-1)
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7922)
*Return type*: bool[.](#21.sentence-1)
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7925)
*Returns*: true if the shared lock was acquired, otherwise false[.](#22.sentence-1)
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7929)
*Throws*: Nothing[.](#23.sentence-1)

View File

@@ -0,0 +1,52 @@
[thread.sharedtimedmutex.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedtimedmutex.class)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedtimedmutex.class)
#### 32.6.4.5 Shared timed mutex types [[thread.sharedtimedmutex.requirements]](thread.sharedtimedmutex.requirements#thread.sharedtimedmutex.class)
#### 32.6.4.5.2 Class shared_timed_mutex [thread.sharedtimedmutex.class]
[🔗](#lib:shared_timed_mutex)
namespace std {class shared_timed_mutex {public: shared_timed_mutex(); ~shared_timed_mutex();
shared_timed_mutex(const shared_timed_mutex&) = delete;
shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); template<class Rep, class Period>bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock_shared(); };}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8123)
The class shared_timed_mutex provides a non-recursive mutex with shared
ownership semantics[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8127)
The class shared_timed_mutex meets
all of the shared timed mutex requirements ([[thread.sharedtimedmutex.requirements]](thread.sharedtimedmutex.requirements "32.6.4.5Shared timed mutex types"))[.](#2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8132)
The behavior of a program is undefined if
- [(3.1)](#3.1)
it destroys a shared_timed_mutex object owned by any thread,
- [(3.2)](#3.2)
a thread attempts to recursively gain any ownership of a shared_timed_mutex, or
- [(3.3)](#3.3)
a thread terminates while possessing any ownership of a shared_timed_mutex[.](#3.sentence-1)

View File

@@ -0,0 +1,201 @@
[thread.sharedtimedmutex.requirements]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedtimedmutex.requirements)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedtimedmutex.requirements)
#### 32.6.4.5 Shared timed mutex types [thread.sharedtimedmutex.requirements]
#### [32.6.4.5.1](#general) General [[thread.sharedtimedmutex.requirements.general]](thread.sharedtimedmutex.requirements.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7987)
The standard library type shared_timed_mutex is a[*shared timed mutex type*](#def:shared_timed_mutex_type "32.6.4.5.1General[thread.sharedtimedmutex.requirements.general]")[.](#general-1.sentence-1)
Shared timed mutex types meet the requirements of
timed mutex types ([[thread.timedmutex.requirements]](thread.timedmutex.requirements "32.6.4.3Timed mutex types")),
shared mutex types ([[thread.sharedmutex.requirements]](thread.sharedmutex.requirements "32.6.4.4Shared mutex types")), and additionally
meet the requirements set out below[.](#general-1.sentence-2)
In this description,m denotes an object of a shared timed mutex type,rel_time denotes an object of an instantiation ofduration ([[time.duration]](time.duration "30.5Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6Class template time_­point[time.point]")[.](#general-1.sentence-3)
[*Note [1](#general-note-1)*:
The shared timed mutex types meet the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#general-1.sentence-4)
— *end note*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8003)
The expression m.try_lock_shared_for(rel_time) is well-formed and
has the following semantics:
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8007)
*Preconditions*: The calling thread has no ownership of the mutex[.](#general-3.sentence-1)
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8011)
*Effects*: Attempts to obtain
shared lock ownership for the calling thread within the relative
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#general-4.sentence-1)
If the time
specified by rel_time is less than or equal to rel_time.zero(),
the function attempts to obtain ownership without blocking (as if by callingtry_lock_shared())[.](#general-4.sentence-2)
The function returns within the timeout
specified by rel_time only if it has obtained shared ownership of the
mutex object[.](#general-4.sentence-3)
[*Note [2](#general-note-2)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#general-4.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#general-4.sentence-5)
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8029)
*Synchronization*: If try_lock_shared_for() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#general-5.sentence-1)
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8035)
*Return type*: bool[.](#general-6.sentence-1)
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8038)
*Returns*: true if the shared lock was acquired, otherwise false[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8042)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#general-8.sentence-1)
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8047)
The expression m.try_lock_shared_until(abs_time) is well-formed
and has the following semantics:
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8051)
*Preconditions*: The calling thread has no ownership of the mutex[.](#general-10.sentence-1)
[11](#general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8055)
*Effects*: The function attempts to obtain shared ownership of the mutex[.](#general-11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain shared
ownership without blocking (as if by calling try_lock_shared())[.](#general-11.sentence-2)
The
function returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by abs_time only if it has obtained shared ownership of the
mutex object[.](#general-11.sentence-3)
[*Note [3](#general-note-3)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#general-11.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#general-11.sentence-5)
[12](#general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8071)
*Synchronization*: If try_lock_shared_until() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#general-12.sentence-1)
[13](#general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8077)
*Return type*: bool[.](#general-13.sentence-1)
[14](#general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8080)
*Returns*: true if the shared lock was acquired, otherwise false[.](#general-14.sentence-1)
[15](#general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8084)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#general-15.sentence-1)
#### [32.6.4.5.2](#thread.sharedtimedmutex.class) Class shared_timed_mutex [[thread.sharedtimedmutex.class]](thread.sharedtimedmutex.class)
[🔗](#lib:shared_timed_mutex)
namespace std {class shared_timed_mutex {public: shared_timed_mutex(); ~shared_timed_mutex();
shared_timed_mutex(const shared_timed_mutex&) = delete;
shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); template<class Rep, class Period>bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock_shared(); };}
[1](#thread.sharedtimedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8123)
The class shared_timed_mutex provides a non-recursive mutex with shared
ownership semantics[.](#thread.sharedtimedmutex.class-1.sentence-1)
[2](#thread.sharedtimedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8127)
The class shared_timed_mutex meets
all of the shared timed mutex requirements ([thread.sharedtimedmutex.requirements])[.](#thread.sharedtimedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.sharedtimedmutex.class-2.sentence-2)
[3](#thread.sharedtimedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8132)
The behavior of a program is undefined if
- [(3.1)](#thread.sharedtimedmutex.class-3.1)
it destroys a shared_timed_mutex object owned by any thread,
- [(3.2)](#thread.sharedtimedmutex.class-3.2)
a thread attempts to recursively gain any ownership of a shared_timed_mutex, or
- [(3.3)](#thread.sharedtimedmutex.class-3.3)
a thread terminates while possessing any ownership of a shared_timed_mutex[.](#thread.sharedtimedmutex.class-3.sentence-1)

View File

@@ -0,0 +1,158 @@
[thread.sharedtimedmutex.requirements.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.sharedtimedmutex.requirements.general)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.sharedtimedmutex.requirements.general)
#### 32.6.4.5 Shared timed mutex types [[thread.sharedtimedmutex.requirements]](thread.sharedtimedmutex.requirements#general)
#### 32.6.4.5.1 General [thread.sharedtimedmutex.requirements.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7987)
The standard library type shared_timed_mutex is a[*shared timed mutex type*](#def:shared_timed_mutex_type "32.6.4.5.1General[thread.sharedtimedmutex.requirements.general]")[.](#1.sentence-1)
Shared timed mutex types meet the requirements of
timed mutex types ([[thread.timedmutex.requirements]](thread.timedmutex.requirements "32.6.4.3Timed mutex types")),
shared mutex types ([[thread.sharedmutex.requirements]](thread.sharedmutex.requirements "32.6.4.4Shared mutex types")), and additionally
meet the requirements set out below[.](#1.sentence-2)
In this description,m denotes an object of a shared timed mutex type,rel_time denotes an object of an instantiation ofduration ([[time.duration]](time.duration "30.5Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6Class template time_­point[time.point]")[.](#1.sentence-3)
[*Note [1](#note-1)*:
The shared timed mutex types meet the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#1.sentence-4)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8003)
The expression m.try_lock_shared_for(rel_time) is well-formed and
has the following semantics:
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8007)
*Preconditions*: The calling thread has no ownership of the mutex[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8011)
*Effects*: Attempts to obtain
shared lock ownership for the calling thread within the relative
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#4.sentence-1)
If the time
specified by rel_time is less than or equal to rel_time.zero(),
the function attempts to obtain ownership without blocking (as if by callingtry_lock_shared())[.](#4.sentence-2)
The function returns within the timeout
specified by rel_time only if it has obtained shared ownership of the
mutex object[.](#4.sentence-3)
[*Note [2](#note-2)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#4.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#4.sentence-5)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8029)
*Synchronization*: If try_lock_shared_for() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8035)
*Return type*: bool[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8038)
*Returns*: true if the shared lock was acquired, otherwise false[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8042)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8047)
The expression m.try_lock_shared_until(abs_time) is well-formed
and has the following semantics:
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8051)
*Preconditions*: The calling thread has no ownership of the mutex[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8055)
*Effects*: The function attempts to obtain shared ownership of the mutex[.](#11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain shared
ownership without blocking (as if by calling try_lock_shared())[.](#11.sentence-2)
The
function returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by abs_time only if it has obtained shared ownership of the
mutex object[.](#11.sentence-3)
[*Note [3](#note-3)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#11.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#11.sentence-5)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8071)
*Synchronization*: If try_lock_shared_until() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8077)
*Return type*: bool[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8080)
*Returns*: true if the shared lock was acquired, otherwise false[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8084)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#15.sentence-1)

View File

@@ -0,0 +1,871 @@
[thread.stoptoken]
# 32 Concurrency support library [[thread]](./#thread)
## 32.3 Stop tokens [thread.stoptoken]
### [32.3.1](#intro) Introduction [[thread.stoptoken.intro]](thread.stoptoken.intro)
[1](#intro-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L449)
Subclause [thread.stoptoken] describes components that can be used
to asynchronously request that an operation stops execution in a timely manner,
typically because the result is no longer required[.](#intro-1.sentence-1)
Such a request is called a [*stop request*](#def:stop_request "32.3.1Introduction[thread.stoptoken.intro]")[.](#intro-1.sentence-2)
[2](#intro-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L455)
The concepts[*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), and[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") specify the required syntax and semantics of
shared access to a [*stop state*](#def:stop_state "32.3.1Introduction[thread.stoptoken.intro]")[.](#intro-2.sentence-1)
Any object modeling [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), or[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") that refers to the same stop state is
an [*associated*](#def:associated "32.3.1Introduction[thread.stoptoken.intro]")[*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), or[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]"),
respectively[.](#intro-2.sentence-2)
[3](#intro-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L472)
An object of a type that models [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") can be passed to an operation that can either
- [(3.1)](#intro-3.1)
actively poll the token to check if there has been a stop request, or
- [(3.2)](#intro-3.2)
register a callback that
will be called in the event that a stop request is made[.](#intro-3.sentence-1)
A stop request made via an object
whose type models [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") will be visible to
all associated [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") and[*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") objects[.](#intro-3.sentence-2)
Once a stop request has been made it cannot be withdrawn
(a subsequent stop request has no effect)[.](#intro-3.sentence-3)
[4](#intro-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L488)
Callbacks registered via an object
whose type models [*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") are called when a stop request is first made
by any associated [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") object[.](#intro-4.sentence-1)
[5](#intro-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L494)
The types stop_source and stop_token and
the class template stop_callback implement
the semantics of shared ownership of a stop state[.](#intro-5.sentence-1)
The last remaining owner of the stop state automatically releases
the resources associated with the stop state[.](#intro-5.sentence-2)
[6](#intro-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L501)
An object of type inplace_stop_source is the sole owner of its stop state[.](#intro-6.sentence-1)
An object of type inplace_stop_token or
of a specialization of the class template inplace_stop_callback does not participate in ownership of its associated stop state[.](#intro-6.sentence-2)
[*Note [1](#intro-note-1)*:
They are for use when all uses of the associated token and callback objects
are known to nest within the lifetime of the inplace_stop_source object[.](#intro-6.sentence-3)
— *end note*]
### [32.3.2](#syn) Header <stop_token> synopsis [[thread.stoptoken.syn]](thread.stoptoken.syn)
[🔗](#header:%3cstop_token%3e)
namespace std {// [[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"), stop token conceptstemplate<class CallbackFn, class Token, class Initializer = CallbackFn>concept [*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; // *exposition only*template<class Token>concept [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; template<class Token>concept [unstoppable_token](#concept:unstoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; template<class Source>concept [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; // *exposition only*// [[stoptoken]](#stoptoken "32.3.4Class stop_­token"), class stop_tokenclass stop_token; // [[stopsource]](#stopsource "32.3.5Class stop_­source"), class stop_sourceclass stop_source; // no-shared-stop-state indicatorstruct nostopstate_t {explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; // [[stopcallback]](#stopcallback "32.3.6Class template stop_­callback"), class template stop_callbacktemplate<class Callback>class stop_callback; // [[stoptoken.never]](#stoptoken.never "32.3.7Class never_­stop_­token"), class never_stop_tokenclass never_stop_token; // [[stoptoken.inplace]](#stoptoken.inplace "32.3.8Class inplace_­stop_­token"), class inplace_stop_tokenclass inplace_stop_token; // [[stopsource.inplace]](#stopsource.inplace "32.3.9Class inplace_­stop_­source"), class inplace_stop_sourceclass inplace_stop_source; // [[stopcallback.inplace]](#stopcallback.inplace "32.3.10Class template inplace_­stop_­callback"), class template inplace_stop_callbacktemplate<class CallbackFn>class inplace_stop_callback; template<class T, class CallbackFn>using stop_callback_for_t = T::template callback_type<CallbackFn>;}
### [32.3.3](#stoptoken.concepts) Stop token concepts [[stoptoken.concepts]](stoptoken.concepts)
[1](#stoptoken.concepts-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L566)
The exposition-only [*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") concept
checks for a callback compatible with a given Token type[.](#stoptoken.concepts-1.sentence-1)
template<class CallbackFn, class Token, class Initializer = CallbackFn>concept [*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") = // *exposition only*[invocable](concept.invocable#concept:invocable "18.7.2Concept invocable[concept.invocable]")<CallbackFn> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<CallbackFn, Initializer> &&requires { typename stop_callback_for_t<Token, CallbackFn>; } &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<stop_callback_for_t<Token, CallbackFn>, const Token&, Initializer>;
[2](#stoptoken.concepts-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L578)
Let t and u be distinct, valid objects of type Token that reference the same logical stop state;
let init be an expression such that[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(init), Initializer> is true; and
let SCB denote the type stop_callback_for_t<Token, CallbackFn>[.](#stoptoken.concepts-2.sentence-1)
[3](#stoptoken.concepts-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L585)
The concept[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, Token, Initializer> is modeled only if:
- [(3.1)](#stoptoken.concepts-3.1)
The following concepts are modeled:
* [(3.1.1)](#stoptoken.concepts-3.1.1)
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<SCB, Token, Initializer>
* [(3.1.2)](#stoptoken.concepts-3.1.2)
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<SCB, Token&, Initializer>
* [(3.1.3)](#stoptoken.concepts-3.1.3)
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<SCB, const Token, Initializer>
- [(3.2)](#stoptoken.concepts-3.2)
An object of type SCB has
an associated callback function of type CallbackFn[.](#stoptoken.concepts-3.2.sentence-1)
Let scb be an object of type SCB and
let callback_fn denote scb's associated callback function[.](#stoptoken.concepts-3.2.sentence-2)
Direct-non-list-initializing scb from
arguments t and init shall execute a [*stoppable callback registration*](#def:registration,stoppable_callback "32.3.3Stop token concepts[stoptoken.concepts]") as follows:
* [(3.2.1)](#stoptoken.concepts-3.2.1)
If t.stop_possible() is true:
+
[(3.2.1.1)](#stoptoken.concepts-3.2.1.1)
callback_fn shall be direct-initialized with init[.](#stoptoken.concepts-3.2.1.1.sentence-1)
+
[(3.2.1.2)](#stoptoken.concepts-3.2.1.2)
Construction of scb shall only throw exceptions
thrown by the initialization of callback_fn from init[.](#stoptoken.concepts-3.2.1.2.sentence-1)
+
[(3.2.1.3)](#stoptoken.concepts-3.2.1.3)
The callback invocation std::forward<CallbackFn>(callback_fn)() shall be registered with t's associated stop state as follows:
- [(3.2.1.3.1)](#stoptoken.concepts-3.2.1.3.1)
If t.stop_requested() evaluates to false at the time of registration,
the callback invocation is added to the stop state's list of callbacks
such that std::forward<CallbackFn>(
callback_fn)() is evaluated
if a stop request is made on the stop state[.](#stoptoken.concepts-3.2.1.3.1.sentence-1)
- [(3.2.1.3.2)](#stoptoken.concepts-3.2.1.3.2)
Otherwise, std::forward<CallbackFn>(callback_fn)() shall be immediately evaluated
on the thread executing scb's constructor, and
the callback invocation shall not be added to the list of callback invocations[.](#stoptoken.concepts-3.2.1.3.2.sentence-1)
If the callback invocation was added to stop state's list of callbacks,scb shall be associated with the stop state[.](#stoptoken.concepts-3.2.1.3.sentence-2)
* [(3.2.2)](#stoptoken.concepts-3.2.2)
[*Note [1](#stoptoken.concepts-note-1)*:
If t.stop_possible() is false,
there is no requirement
that the initialization of scb causes the initialization of callback_fn[.](#stoptoken.concepts-3.2.2.sentence-1)
— *end note*]
- [(3.3)](#stoptoken.concepts-3.3)
Destruction of scb shall execute
a [*stoppable callback deregistration*](#def:callback_deregistration,stoppable "32.3.3Stop token concepts[stoptoken.concepts]") as follows (in order):
* [(3.3.1)](#stoptoken.concepts-3.3.1)
If the constructor of scb did not register
a callback invocation with t's stop state,
then the stoppable callback deregistration shall have no effect
other than destroying callback_fn if it was constructed[.](#stoptoken.concepts-3.3.1.sentence-1)
* [(3.3.2)](#stoptoken.concepts-3.3.2)
Otherwise, the invocation of callback_fn shall be removed
from the associated stop state[.](#stoptoken.concepts-3.3.2.sentence-1)
* [(3.3.3)](#stoptoken.concepts-3.3.3)
If callback_fn is concurrently executing on another thread,
then the stoppable callback deregistration shall block ([[defns.block]](defns.block "3.6block"))
until the invocation of callback_fn returns
such that the return from the invocation of callback_fn strongly happens before ([[intro.races]](intro.races "6.10.2.2Data races"))
the destruction of callback_fn[.](#stoptoken.concepts-3.3.3.sentence-1)
* [(3.3.4)](#stoptoken.concepts-3.3.4)
If callback_fn is executing on the current thread,
then the destructor shall not block
waiting for the return from the invocation of callback_fn[.](#stoptoken.concepts-3.3.4.sentence-1)
* [(3.3.5)](#stoptoken.concepts-3.3.5)
A stoppable callback deregistration shall not block
on the completion of the invocation of some other callback
registered with the same logical stop state[.](#stoptoken.concepts-3.3.5.sentence-1)
* [(3.3.6)](#stoptoken.concepts-3.3.6)
The stoppable callback deregistration shall destroy callback_fn[.](#stoptoken.concepts-3.3.6.sentence-1)
[4](#stoptoken.concepts-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L675)
The [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") concept checks
for the basic interface of a stop token
that is copyable and allows polling to see if stop has been requested and
also whether a stop request is possible[.](#stoptoken.concepts-4.sentence-1)
The [unstoppable_token](#concept:unstoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") concept checks
for a [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") type that does not allow stopping[.](#stoptoken.concepts-4.sentence-2)
template<template<class> class>struct *check-type-alias-exists*; // *exposition only*template<class Token>concept [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") =requires (const Token tok) {typename *check-type-alias-exists*<Token::template callback_type>; { tok.stop_requested() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; { tok.stop_possible() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; { Token(tok) } noexcept; // see implicit expression variations ([[concepts.equality]](concepts.equality "18.2Equality preservation"))} &&[copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<Token> &&[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<Token>;
template<class Token>concept [unstoppable_token](#concept:unstoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") =[stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]")<Token> &&requires (const Token tok) {requires bool_constant<(!tok.stop_possible())>::value; };
[5](#stoptoken.concepts-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L705)
An object whose type models [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") has at most one associated logical stop state[.](#stoptoken.concepts-5.sentence-1)
A [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") object with no associated stop state
is said to be [*disengaged*](#def:disengaged "32.3.3Stop token concepts[stoptoken.concepts]")[.](#stoptoken.concepts-5.sentence-2)
[6](#stoptoken.concepts-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L711)
Let SP be an evaluation of t.stop_possible() that is false, and
let SR be an evaluation of t.stop_requested() that is true[.](#stoptoken.concepts-6.sentence-1)
[7](#stoptoken.concepts-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L716)
The type Token models [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") only if:
- [(7.1)](#stoptoken.concepts-7.1)
Any evaluation of u.stop_possible() or u.stop_requested() that happens after ([[intro.races]](intro.races "6.10.2.2Data races")) SP is false[.](#stoptoken.concepts-7.1.sentence-1)
- [(7.2)](#stoptoken.concepts-7.2)
Any evaluation of u.stop_possible() or u.stop_requested() that happens after SR is true[.](#stoptoken.concepts-7.2.sentence-1)
- [(7.3)](#stoptoken.concepts-7.3)
For any types CallbackFn and Initializer such that[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, Token, Initializer> is satisfied,[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, Token, Initializer> is modeled[.](#stoptoken.concepts-7.3.sentence-1)
- [(7.4)](#stoptoken.concepts-7.4)
If t is disengaged,
evaluations of t.stop_possible() and t.stop_requested() are false[.](#stoptoken.concepts-7.4.sentence-1)
- [(7.5)](#stoptoken.concepts-7.5)
If t and u reference the same stop state, or
if both t and u are disengaged,t == u is true; otherwise, it is false[.](#stoptoken.concepts-7.5.sentence-1)
[8](#stoptoken.concepts-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L741)
An object
whose type models the exposition-only [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") concept
can be queried
whether stop has been requested (stop_requested) and
whether stop is possible (stop_possible)[.](#stoptoken.concepts-8.sentence-1)
It is a factory for associated stop tokens (get_token), and
a stop request can be made on it (request_stop)[.](#stoptoken.concepts-8.sentence-2)
It maintains a list of registered stop callback invocations
that it executes when a stop request is first made[.](#stoptoken.concepts-8.sentence-3)
template<class Source>concept [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") = // *exposition only*requires (Source& src, const Source csrc) { // see implicit expression variations ([[concepts.equality]](concepts.equality "18.2Equality preservation")){ csrc.get_token() } -> stoppable_token; { csrc.stop_possible() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; { csrc.stop_requested() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; { src.request_stop() } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; };
[9](#stoptoken.concepts-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L762)
An object whose type models [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") has
at most one associated logical stop state[.](#stoptoken.concepts-9.sentence-1)
If it has no associated stop state, it is said to be disengaged[.](#stoptoken.concepts-9.sentence-2)
Let s be an object whose type models [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") and
that is disengaged[.](#stoptoken.concepts-9.sentence-3)
s.stop_possible() and s.stop_requested() shall be false[.](#stoptoken.concepts-9.sentence-4)
[10](#stoptoken.concepts-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L770)
Let t be an object whose type models [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]")[.](#stoptoken.concepts-10.sentence-1)
If t is disengaged,t.get_token() shall return a disengaged stop token;
otherwise, it shall return
a stop token that is associated with the stop state of t[.](#stoptoken.concepts-10.sentence-2)
[11](#stoptoken.concepts-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L777)
Calls to the member functionsrequest_stop, stop_requested, and stop_possible and
similarly named member functions
on associated [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") objects
do not introduce data races[.](#stoptoken.concepts-11.sentence-1)
A call to request_stop that returns true synchronizes with
a call to stop_requested on
an associated[stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") or [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") object
that returns true[.](#stoptoken.concepts-11.sentence-2)
Registration of a callback synchronizes with the invocation of that callback[.](#stoptoken.concepts-11.sentence-3)
[12](#stoptoken.concepts-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L790)
If the [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") is disengaged,request_stop shall have no effect and return false[.](#stoptoken.concepts-12.sentence-1)
Otherwise, it shall execute a [*stop request operation*](#def:operation,stop_request "32.3.3Stop token concepts[stoptoken.concepts]") on the associated stop state[.](#stoptoken.concepts-12.sentence-2)
A stop request operation determines
whether the stop state has received a stop request, and
if not, makes a stop request[.](#stoptoken.concepts-12.sentence-3)
The determination and making of the stop request shall happen atomically,
as-if by a read-modify-write operation ([[intro.races]](intro.races "6.10.2.2Data races"))[.](#stoptoken.concepts-12.sentence-4)
If the request was made,
the stop state's registered callback invocations shall be
synchronously executed[.](#stoptoken.concepts-12.sentence-5)
If an invocation of a callback exits via an exception
then terminate shall be invoked ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#stoptoken.concepts-12.sentence-6)
[*Note [2](#stoptoken.concepts-note-2)*:
No constraint is placed on the order
in which the callback invocations are executed[.](#stoptoken.concepts-12.sentence-7)
— *end note*]
request_stop shall return true if a stop request was made, andfalse otherwise[.](#stoptoken.concepts-12.sentence-8)
After a call to request_stop either
a call to stop_possible shall return false or
a call to stop_requested shall return true[.](#stoptoken.concepts-12.sentence-9)
[*Note [3](#stoptoken.concepts-note-3)*:
A stop request includes notifying
all condition variables of type condition_variable_any temporarily registered during
an interruptible wait ([[thread.condvarany.intwait]](thread.condvarany.intwait "32.7.5.3Interruptible waits"))[.](#stoptoken.concepts-12.sentence-10)
— *end note*]
### [32.3.4](#stoptoken) Class stop_token [[stoptoken]](stoptoken)
#### [32.3.4.1](#stoptoken.general) General [[stoptoken.general]](stoptoken.general)
[1](#stoptoken.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L826)
The class stop_token models the concept [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]")[.](#stoptoken.general-1.sentence-1)
It shares ownership of its stop state, if any,
with its associated stop_source object ([[stopsource]](#stopsource "32.3.5Class stop_­source")) and
any stop_token objects to which it compares equal[.](#stoptoken.general-1.sentence-2)
namespace std {class stop_token {public:template<class CallbackFn>using callback_type = stop_callback<CallbackFn>;
stop_token() noexcept = default; // [[stoptoken.mem]](#stoptoken.mem "32.3.4.2Member functions"), member functionsvoid swap(stop_token&) noexcept; bool stop_requested() const noexcept; bool stop_possible() const noexcept; bool operator==(const stop_token& rhs) noexcept = default; private: shared_ptr<*unspecified*> *stop-state*; // *exposition only*};}
[2](#stoptoken.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L856)
*stop-state* refers to the stop_token's associated stop state[.](#stoptoken.general-2.sentence-1)
A stop_token object is disengaged when *stop-state* is empty[.](#stoptoken.general-2.sentence-2)
#### [32.3.4.2](#stoptoken.mem) Member functions [[stoptoken.mem]](stoptoken.mem)
[🔗](#lib:swap,stop_token)
`void swap(stop_token& rhs) noexcept;
`
[1](#stoptoken.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L868)
*Effects*: Equivalent to:*stop-state*.swap(rhs.*stop-state*);
[🔗](#lib:stop_requested,stop_token)
`bool stop_requested() const noexcept;
`
[2](#stoptoken.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L882)
*Returns*: true if *stop-state* refers to a stop state
that has received a stop request;
otherwise, false[.](#stoptoken.mem-2.sentence-1)
[🔗](#lib:stop_possible,stop_token)
`bool stop_possible() const noexcept;
`
[3](#stoptoken.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L895)
*Returns*: false if
- [(3.1)](#stoptoken.mem-3.1)
*this is disengaged, or
- [(3.2)](#stoptoken.mem-3.2)
a stop request was not made
and there are no associated stop_source objects;
otherwise, true[.](#stoptoken.mem-3.sentence-1)
### [32.3.5](#stopsource) Class stop_source [[stopsource]](stopsource)
#### [32.3.5.1](#stopsource.general) General [[stopsource.general]](stopsource.general)
namespace std {class stop_source {public:// [[stopsource.cons]](#stopsource.cons "32.3.5.2Constructors, copy, and assignment"), constructors, copy, and assignment stop_source(); explicit stop_source(nostopstate_t) noexcept {}// [[stopsource.mem]](#stopsource.mem "32.3.5.3Member functions"), member functionsvoid swap(stop_source&) noexcept;
stop_token get_token() const noexcept; bool stop_possible() const noexcept; bool stop_requested() const noexcept; bool request_stop() noexcept; bool operator==(const stop_source& rhs) noexcept = default; private: shared_ptr<*unspecified*> *stop-state*; // *exposition only*};}
[1](#stopsource.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L935)
*stop-state* refers to the stop_source's associated stop state[.](#stopsource.general-1.sentence-1)
A stop_source object is disengaged when *stop-state* is empty[.](#stopsource.general-1.sentence-2)
[2](#stopsource.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L939)
stop_source models[*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]"),[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]"), and[swappable](concept.swappable#concept:swappable "18.4.9Concept swappable[concept.swappable]")[.](#stopsource.general-2.sentence-1)
#### [32.3.5.2](#stopsource.cons) Constructors, copy, and assignment [[stopsource.cons]](stopsource.cons)
[🔗](#lib:stop_source,constructor)
`stop_source();
`
[1](#stopsource.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L954)
*Effects*: Initializes *stop-state* with a pointer to a new stop state[.](#stopsource.cons-1.sentence-1)
[2](#stopsource.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L958)
*Postconditions*: stop_possible() is true and stop_requested() is false[.](#stopsource.cons-2.sentence-1)
[3](#stopsource.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L963)
*Throws*: bad_alloc if memory cannot be allocated for the stop state[.](#stopsource.cons-3.sentence-1)
#### [32.3.5.3](#stopsource.mem) Member functions [[stopsource.mem]](stopsource.mem)
[🔗](#lib:swap,stop_source)
`void swap(stop_source& rhs) noexcept;
`
[1](#stopsource.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L976)
*Effects*: Equivalent to:*stop-state*.swap(rhs.*stop-state*);
[🔗](#lib:get_token,stop_source)
`stop_token get_token() const noexcept;
`
[2](#stopsource.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L990)
*Returns*: stop_token() if stop_possible() is false;
otherwise a new associated stop_token object;
i.e., its *stop-state* member is equal to
the *stop-state* member of *this[.](#stopsource.mem-2.sentence-1)
[🔗](#lib:stop_possible,stop_source)
`bool stop_possible() const noexcept;
`
[3](#stopsource.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1004)
*Returns*: *stop-state* != nullptr[.](#stopsource.mem-3.sentence-1)
[🔗](#lib:stop_requested,stop_source)
`bool stop_requested() const noexcept;
`
[4](#stopsource.mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1015)
*Returns*: true if *stop-state* refers to a stop state
that has received a stop request;
otherwise, false[.](#stopsource.mem-4.sentence-1)
[🔗](#lib:request_stop,stop_source)
`bool request_stop() noexcept;
`
[5](#stopsource.mem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1028)
*Effects*: Executes a stop request operation ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts")) on
the associated stop state, if any[.](#stopsource.mem-5.sentence-1)
### [32.3.6](#stopcallback) Class template stop_callback [[stopcallback]](stopcallback)
#### [32.3.6.1](#stopcallback.general) General [[stopcallback.general]](stopcallback.general)
[1](#stopcallback.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1039)
[🔗](#lib:stop_callback_)
namespace std {template<class CallbackFn>class stop_callback {public:using callback_type = CallbackFn; // [[stopcallback.cons]](#stopcallback.cons "32.3.6.2Constructors and destructor"), constructors and destructortemplate<class Initializer>explicit stop_callback(const stop_token& st, Initializer&& init)noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); template<class Initializer>explicit stop_callback(stop_token&& st, Initializer&& init)noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); ~stop_callback();
stop_callback(const stop_callback&) = delete;
stop_callback(stop_callback&&) = delete;
stop_callback& operator=(const stop_callback&) = delete;
stop_callback& operator=(stop_callback&&) = delete; private: CallbackFn *callback-fn*; // *exposition only*}; template<class CallbackFn> stop_callback(stop_token, CallbackFn) -> stop_callback<CallbackFn>;}
[2](#stopcallback.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1071)
*Mandates*: stop_callback is instantiated with an argument for the
template parameter CallbackFn that satisfies both [invocable](concept.invocable#concept:invocable "18.7.2Concept invocable[concept.invocable]") and [destructible](concept.destructible#concept:destructible "18.4.10Concept destructible[concept.destructible]")[.](#stopcallback.general-2.sentence-1)
[3](#stopcallback.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1078)
*Remarks*: For a type Initializer,
if[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, stop_token, Initializer> is satisfied, then[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, stop_token, Initializer> is modeled[.](#stopcallback.general-3.sentence-1)
The exposition-only *callback-fn* member is
the associated callback function ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts")) ofstop_callback<
CallbackFn> objects[.](#stopcallback.general-3.sentence-2)
#### [32.3.6.2](#stopcallback.cons) Constructors and destructor [[stopcallback.cons]](stopcallback.cons)
[🔗](#lib:stop_callback,constructor)
`template<class Initializer>
explicit stop_callback(const stop_token& st, Initializer&& init)
noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>);
template<class Initializer>
explicit stop_callback(stop_token&& st, Initializer&& init)
noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>);
`
[1](#stopcallback.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1103)
*Constraints*: CallbackFn and Initializer satisfy[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<CallbackFn, Initializer>[.](#stopcallback.cons-1.sentence-1)
[2](#stopcallback.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1108)
*Effects*: Initializes *callback-fn* with std::forward<Initializer>(init) and executes a stoppable callback registration ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"))[.](#stopcallback.cons-2.sentence-1)
If a callback is registered with st's shared stop state,
then *this acquires shared ownership of that stop state[.](#stopcallback.cons-2.sentence-2)
[🔗](#lib:stop_callback,destructor)
`~stop_callback();
`
[3](#stopcallback.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1122)
*Effects*: Executes a stoppable callback deregistration ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts")) and
releases ownership of the stop state, if any[.](#stopcallback.cons-3.sentence-1)
### [32.3.7](#stoptoken.never) Class never_stop_token [[stoptoken.never]](stoptoken.never)
[1](#stoptoken.never-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1130)
The class never_stop_token models
the [unstoppable_token](#concept:unstoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") concept[.](#stoptoken.never-1.sentence-1)
It provides a stop token interface,
but also provides static information
that a stop is never possible nor requested[.](#stoptoken.never-1.sentence-2)
namespace std {class never_stop_token {struct *callback-type* { // *exposition only*explicit *callback-type*(never_stop_token, auto&&) noexcept {}}; public:template<class>using callback_type = *callback-type*; static constexpr bool stop_requested() noexcept { return false; }static constexpr bool stop_possible() noexcept { return false; }bool operator==(const never_stop_token&) const = default; };}
### [32.3.8](#stoptoken.inplace) Class inplace_stop_token [[stoptoken.inplace]](stoptoken.inplace)
#### [32.3.8.1](#stoptoken.inplace.general) General [[stoptoken.inplace.general]](stoptoken.inplace.general)
[1](#stoptoken.inplace.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1158)
The class inplace_stop_token models
the concept [stoppable_token](#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]")[.](#stoptoken.inplace.general-1.sentence-1)
It references the stop state of
its associated inplace_stop_source object ([[stopsource.inplace]](#stopsource.inplace "32.3.9Class inplace_­stop_­source")),
if any[.](#stoptoken.inplace.general-1.sentence-2)
namespace std {class inplace_stop_token {public:template<class CallbackFn>using callback_type = inplace_stop_callback<CallbackFn>;
inplace_stop_token() = default; bool operator==(const inplace_stop_token&) const = default; // [[stoptoken.inplace.mem]](#stoptoken.inplace.mem "32.3.8.2Member functions"), member functionsbool stop_requested() const noexcept; bool stop_possible() const noexcept; void swap(inplace_stop_token&) noexcept; private:const inplace_stop_source* *stop-source* = nullptr; // *exposition only*};}
#### [32.3.8.2](#stoptoken.inplace.mem) Member functions [[stoptoken.inplace.mem]](stoptoken.inplace.mem)
[🔗](#stoptoken.inplace.mem-itemdecl:1)
`void swap(inplace_stop_token& rhs) noexcept;
`
[1](#stoptoken.inplace.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1192)
*Effects*: Exchanges the values of *stop-source* and rhs.*stop-source*[.](#stoptoken.inplace.mem-1.sentence-1)
[🔗](#stoptoken.inplace.mem-itemdecl:2)
`bool stop_requested() const noexcept;
`
[2](#stoptoken.inplace.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1202)
*Effects*: Equivalent to:return *stop-source* != nullptr && *stop-source*->stop_requested();
[3](#stoptoken.inplace.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1209)
[*Note [1](#stoptoken.inplace.mem-note-1)*:
As specified in [[basic.life]](basic.life "6.8.4Lifetime"),
the behavior of stop_requested is undefined
unless the call strongly happens before the start of
the destructor of the associated inplace_stop_source object, if any[.](#stoptoken.inplace.mem-3.sentence-1)
— *end note*]
[🔗](#stoptoken.inplace.mem-itemdecl:3)
`stop_possible() const noexcept;
`
[4](#stoptoken.inplace.mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1223)
*Returns*: *stop-source* != nullptr[.](#stoptoken.inplace.mem-4.sentence-1)
[5](#stoptoken.inplace.mem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1227)
[*Note [2](#stoptoken.inplace.mem-note-2)*:
As specified in [[basic.stc.general]](basic.stc.general "6.8.6.1General"),
the behavior of stop_possible is implementation-defined
unless the call strongly happens before
the end of the storage duration of
the associated inplace_stop_source object, if any[.](#stoptoken.inplace.mem-5.sentence-1)
— *end note*]
### [32.3.9](#stopsource.inplace) Class inplace_stop_source [[stopsource.inplace]](stopsource.inplace)
#### [32.3.9.1](#stopsource.inplace.general) General [[stopsource.inplace.general]](stopsource.inplace.general)
[1](#stopsource.inplace.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1241)
The class inplace_stop_source models [*stoppable-source*](#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]")[.](#stopsource.inplace.general-1.sentence-1)
namespace std {class inplace_stop_source {public:// [[stopsource.inplace.cons]](#stopsource.inplace.cons "32.3.9.2Constructors"), constructorsconstexpr inplace_stop_source() noexcept;
inplace_stop_source(inplace_stop_source&&) = delete;
inplace_stop_source(const inplace_stop_source&) = delete;
inplace_stop_source& operator=(inplace_stop_source&&) = delete;
inplace_stop_source& operator=(const inplace_stop_source&) = delete; ~inplace_stop_source(); // [[stopsource.inplace.mem]](#stopsource.inplace.mem "32.3.9.3Member functions"), stop handlingconstexpr inplace_stop_token get_token() const noexcept; static constexpr bool stop_possible() noexcept { return true; }bool stop_requested() const noexcept; bool request_stop() noexcept; };}
#### [32.3.9.2](#stopsource.inplace.cons) Constructors [[stopsource.inplace.cons]](stopsource.inplace.cons)
[🔗](#stopsource.inplace.cons-itemdecl:1)
`constexpr inplace_stop_source() noexcept;
`
[1](#stopsource.inplace.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1273)
*Effects*: Initializes a new stop state inside *this[.](#stopsource.inplace.cons-1.sentence-1)
[2](#stopsource.inplace.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1277)
*Postconditions*: stop_requested() is false[.](#stopsource.inplace.cons-2.sentence-1)
#### [32.3.9.3](#stopsource.inplace.mem) Member functions [[stopsource.inplace.mem]](stopsource.inplace.mem)
[🔗](#stopsource.inplace.mem-itemdecl:1)
`constexpr inplace_stop_token get_token() const noexcept;
`
[1](#stopsource.inplace.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1289)
*Returns*: A new associated inplace_stop_token object
whose *stop-source* member is equal to this[.](#stopsource.inplace.mem-1.sentence-1)
[🔗](#stopsource.inplace.mem-itemdecl:2)
`bool stop_requested() const noexcept;
`
[2](#stopsource.inplace.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1300)
*Returns*: true if the stop state inside *this has received a stop request; otherwise, false[.](#stopsource.inplace.mem-2.sentence-1)
[🔗](#stopsource.inplace.mem-itemdecl:3)
`bool request_stop() noexcept;
`
[3](#stopsource.inplace.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1311)
*Effects*: Executes a stop request operation ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"))[.](#stopsource.inplace.mem-3.sentence-1)
[4](#stopsource.inplace.mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1315)
*Postconditions*: stop_requested() is true[.](#stopsource.inplace.mem-4.sentence-1)
### [32.3.10](#stopcallback.inplace) Class template inplace_stop_callback [[stopcallback.inplace]](stopcallback.inplace)
#### [32.3.10.1](#stopcallback.inplace.general) General [[stopcallback.inplace.general]](stopcallback.inplace.general)
namespace std {template<class CallbackFn>class inplace_stop_callback {public:using callback_type = CallbackFn; // [[stopcallback.inplace.cons]](#stopcallback.inplace.cons "32.3.10.2Constructors and destructor"), constructors and destructortemplate<class Initializer>explicit inplace_stop_callback(inplace_stop_token st, Initializer&& init)noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); ~inplace_stop_callback();
inplace_stop_callback(inplace_stop_callback&&) = delete;
inplace_stop_callback(const inplace_stop_callback&) = delete;
inplace_stop_callback& operator=(inplace_stop_callback&&) = delete;
inplace_stop_callback& operator=(const inplace_stop_callback&) = delete; private: CallbackFn *callback-fn*; // *exposition only*}; template<class CallbackFn> inplace_stop_callback(inplace_stop_token, CallbackFn)-> inplace_stop_callback<CallbackFn>;}
[1](#stopcallback.inplace.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1352)
*Mandates*: CallbackFn satisfies both[invocable](concept.invocable#concept:invocable "18.7.2Concept invocable[concept.invocable]") and [destructible](concept.destructible#concept:destructible "18.4.10Concept destructible[concept.destructible]")[.](#stopcallback.inplace.general-1.sentence-1)
[2](#stopcallback.inplace.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1357)
*Remarks*: For a type Initializer, if[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, inplace_stop_token, Initializer> is satisfied, then[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<CallbackFn, inplace_stop_token, Initializer> is modeled[.](#stopcallback.inplace.general-2.sentence-1)
For an inplace_stop_callback<CallbackFn> object,
the exposition-only *callback-fn* member is
its associated callback function ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"))[.](#stopcallback.inplace.general-2.sentence-2)
#### [32.3.10.2](#stopcallback.inplace.cons) Constructors and destructor [[stopcallback.inplace.cons]](stopcallback.inplace.cons)
[🔗](#stopcallback.inplace.cons-itemdecl:1)
`template<class Initializer>
explicit inplace_stop_callback(inplace_stop_token st, Initializer&& init)
noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>);
`
[1](#stopcallback.inplace.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1381)
*Constraints*: [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<CallbackFn, Initializer> is satisfied[.](#stopcallback.inplace.cons-1.sentence-1)
[2](#stopcallback.inplace.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1385)
*Effects*: Initializes *callback-fn* with std::forward<Initializer>(init) and executes a stoppable callback registration ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"))[.](#stopcallback.inplace.cons-2.sentence-1)
[🔗](#stopcallback.inplace.cons-itemdecl:2)
`~inplace_stop_callback();
`
[3](#stopcallback.inplace.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1396)
*Effects*: Executes a stoppable callback deregistration ([[stoptoken.concepts]](#stoptoken.concepts "32.3.3Stop token concepts"))[.](#stopcallback.inplace.cons-3.sentence-1)

View File

@@ -0,0 +1,85 @@
[thread.stoptoken.intro]
# 32 Concurrency support library [[thread]](./#thread)
## 32.3 Stop tokens [[thread.stoptoken]](thread.stoptoken#intro)
### 32.3.1 Introduction [thread.stoptoken.intro]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L449)
Subclause [[thread.stoptoken]](thread.stoptoken "32.3Stop tokens") describes components that can be used
to asynchronously request that an operation stops execution in a timely manner,
typically because the result is no longer required[.](#1.sentence-1)
Such a request is called a [*stop request*](#def:stop_request "32.3.1Introduction[thread.stoptoken.intro]")[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L455)
The concepts[*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), and[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") specify the required syntax and semantics of
shared access to a [*stop state*](#def:stop_state "32.3.1Introduction[thread.stoptoken.intro]")[.](#2.sentence-1)
Any object modeling [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), or[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") that refers to the same stop state is
an [*associated*](#def:associated "32.3.1Introduction[thread.stoptoken.intro]")[*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]"), or[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]"),
respectively[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L472)
An object of a type that models [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") can be passed to an operation that can either
- [(3.1)](#3.1)
actively poll the token to check if there has been a stop request, or
- [(3.2)](#3.2)
register a callback that
will be called in the event that a stop request is made[.](#3.sentence-1)
A stop request made via an object
whose type models [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") will be visible to
all associated [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") and[*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") objects[.](#3.sentence-2)
Once a stop request has been made it cannot be withdrawn
(a subsequent stop request has no effect)[.](#3.sentence-3)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L488)
Callbacks registered via an object
whose type models [*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") are called when a stop request is first made
by any associated [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") object[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L494)
The types stop_source and stop_token and
the class template stop_callback implement
the semantics of shared ownership of a stop state[.](#5.sentence-1)
The last remaining owner of the stop state automatically releases
the resources associated with the stop state[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L501)
An object of type inplace_stop_source is the sole owner of its stop state[.](#6.sentence-1)
An object of type inplace_stop_token or
of a specialization of the class template inplace_stop_callback does not participate in ownership of its associated stop state[.](#6.sentence-2)
[*Note [1](#note-1)*:
They are for use when all uses of the associated token and callback objects
are known to nest within the lifetime of the inplace_stop_source object[.](#6.sentence-3)
— *end note*]

View File

@@ -0,0 +1,11 @@
[thread.stoptoken.syn]
# 32 Concurrency support library [[thread]](./#thread)
## 32.3 Stop tokens [[thread.stoptoken]](thread.stoptoken#syn)
### 32.3.2 Header <stop_token> synopsis [thread.stoptoken.syn]
[🔗](#header:%3cstop_token%3e)
namespace std {// [[stoptoken.concepts]](stoptoken.concepts "32.3.3Stop token concepts"), stop token conceptstemplate<class CallbackFn, class Token, class Initializer = CallbackFn>concept [*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; // *exposition only*template<class Token>concept [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; template<class Token>concept [unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; template<class Source>concept [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3Stop token concepts[stoptoken.concepts]") = *see below*; // *exposition only*// [[stoptoken]](stoptoken "32.3.4Class stop_­token"), class stop_tokenclass stop_token; // [[stopsource]](stopsource "32.3.5Class stop_­source"), class stop_sourceclass stop_source; // no-shared-stop-state indicatorstruct nostopstate_t {explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; // [[stopcallback]](stopcallback "32.3.6Class template stop_­callback"), class template stop_callbacktemplate<class Callback>class stop_callback; // [[stoptoken.never]](stoptoken.never "32.3.7Class never_­stop_­token"), class never_stop_tokenclass never_stop_token; // [[stoptoken.inplace]](stoptoken.inplace "32.3.8Class inplace_­stop_­token"), class inplace_stop_tokenclass inplace_stop_token; // [[stopsource.inplace]](stopsource.inplace "32.3.9Class inplace_­stop_­source"), class inplace_stop_sourceclass inplace_stop_source; // [[stopcallback.inplace]](stopcallback.inplace "32.3.10Class template inplace_­stop_­callback"), class template inplace_stop_callbacktemplate<class CallbackFn>class inplace_stop_callback; template<class T, class CallbackFn>using stop_callback_for_t = T::template callback_type<CallbackFn>;}

11
cppdraft/thread/syn.md Normal file
View File

@@ -0,0 +1,11 @@
[thread.syn]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.syn)
### 32.4.2 Header <thread> synopsis [thread.syn]
[🔗](#header:%3cthread%3e)
#include <compare> // see [[compare.syn]](compare.syn "17.12.1Header <compare> synopsis")namespace std {// [[thread.thread.class]](thread.thread.class "32.4.3Class thread"), class threadclass thread; void swap(thread& x, thread& y) noexcept; // [[thread.jthread.class]](thread.jthread.class "32.4.4Class jthread"), class jthreadclass jthread; // [[thread.thread.this]](thread.thread.this "32.4.5Namespace this_­thread"), namespace this_threadnamespace this_thread { thread::id get_id() noexcept; void yield() noexcept; template<class Clock, class Duration>void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period>void sleep_for(const chrono::duration<Rep, Period>& rel_time); }}

View File

@@ -0,0 +1,20 @@
[thread.thread.algorithm]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.algorithm)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.algorithm)
#### 32.4.3.8 Specialized algorithms [thread.thread.algorithm]
[🔗](#lib:swap,thread)
`void swap(thread& x, thread& y) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1915)
*Effects*: As if by x.swap(y)[.](#1.sentence-1)

View File

@@ -0,0 +1,35 @@
[thread.thread.assign]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.assign)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.assign)
#### 32.4.3.5 Assignment [thread.thread.assign]
[🔗](#lib:operator=,thread)
`thread& operator=(thread&& x) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1763)
*Effects*: If joinable(), invokes terminate ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#1.sentence-1)
Otherwise, assigns the
state of x to *this and sets x to a default constructed state[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1769)
*Postconditions*: x.get_id() == id() and get_id() returns the value ofx.get_id() prior to the assignment[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1774)
*Returns*: *this[.](#3.sentence-1)

View File

@@ -0,0 +1,547 @@
[thread.thread.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.class)
### 32.4.3 Class thread [thread.thread.class]
#### [32.4.3.1](#general) General [[thread.thread.class.general]](thread.thread.class.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1443)
The class thread provides a mechanism to create a new thread of execution, to join with
a thread (i.e., wait for a thread to complete), and to perform other operations that manage and
query the state of a thread[.](#general-1.sentence-1)
A thread object uniquely represents a particular thread of
execution[.](#general-1.sentence-2)
That representation may be transferred to other thread objects in such a way
that no two thread objects simultaneously represent the same thread of execution[.](#general-1.sentence-3)
A
thread of execution is [*detached*](#def:detached) when no thread object represents that thread[.](#general-1.sentence-4)
Objects of class thread can be in a state that does not represent a thread of
execution[.](#general-1.sentence-5)
[*Note [1](#general-note-1)*:
A thread object does not represent a thread of execution after
default construction, after being moved from, or after a successful call to detach orjoin[.](#general-1.sentence-6)
— *end note*]
[🔗](#lib:thread)
namespace std {class thread {public:// [[thread.thread.id]](#thread.thread.id "32.4.3.2Class thread::id"), class thread::idclass id; using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// construct/copy/destroy thread() noexcept; template<class F, class... Args> explicit thread(F&& f, Args&&... args); ~thread();
thread(const thread&) = delete;
thread(thread&&) noexcept;
thread& operator=(const thread&) = delete;
thread& operator=(thread&&) noexcept; // [[thread.thread.member]](#thread.thread.member "32.4.3.6Members"), membersvoid swap(thread&) noexcept; bool joinable() const noexcept; void join(); void detach();
id get_id() const noexcept;
native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// static membersstatic unsigned int hardware_concurrency() noexcept; };}
#### [32.4.3.2](#thread.thread.id) Class thread::id [[thread.thread.id]](thread.thread.id)
[🔗](#lib:thread::id)
namespace std {class thread::id {public: id() noexcept; }; bool operator==(thread::id x, thread::id y) noexcept;
strong_ordering operator<=>(thread::id x, thread::id y) noexcept; template<class charT, class traits> basic_ostream<charT, traits>&operator<<(basic_ostream<charT, traits>& out, thread::id id); template<class charT> struct formatter<thread::id, charT>; // hash supporttemplate<class T> struct hash; template<> struct hash<thread::id>;}
[1](#thread.thread.id-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1516)
An object of type thread::id provides a unique identifier for
each thread of execution and a single distinct value for all thread objects that do not represent a thread of
execution ([thread.thread.class])[.](#thread.thread.id-1.sentence-1)
Each thread of execution has an
associated thread::id object that is not equal to thethread::id object of any other thread of execution and that is not
equal to the thread::id object of any thread object that
does not represent threads of execution[.](#thread.thread.id-1.sentence-2)
[2](#thread.thread.id-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1526)
The [*text representation*](#def:text_representation "32.4.3.2Class thread::id[thread.thread.id]") for
the character type charT of an object of type thread::id is an unspecified sequence of charT such that,
for two objects of type thread::id x and y,
if x == y is true,
the thread::id objects have the same text representation, and
if x != y is true,
the thread::id objects have distinct text representations[.](#thread.thread.id-2.sentence-1)
[3](#thread.thread.id-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1536)
thread::id is a trivially copyable class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.thread.id-3.sentence-1)
The library may reuse the value of a thread::id of a terminated thread that can no longer be joined[.](#thread.thread.id-3.sentence-2)
[4](#thread.thread.id-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1540)
[*Note [1](#thread.thread.id-note-1)*:
Relational operators allow thread::id objects to be used as
keys in associative containers[.](#thread.thread.id-4.sentence-1)
— *end note*]
[🔗](#lib:thread::id,constructor)
`id() noexcept;
`
[5](#thread.thread.id-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1552)
*Postconditions*: The constructed object does not represent a thread of execution[.](#thread.thread.id-5.sentence-1)
[🔗](#lib:operator==,thread::id)
`bool operator==(thread::id x, thread::id y) noexcept;
`
[6](#thread.thread.id-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1563)
*Returns*: true only if x and y represent the same
thread of execution or neither x nor y represents a thread of
execution[.](#thread.thread.id-6.sentence-1)
[🔗](#lib:operator%3c=%3e,thread::id)
`strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
`
[7](#thread.thread.id-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1576)
Let P(x, y) be
an unspecified total ordering over thread::id as described in [[alg.sorting]](alg.sorting "26.8Sorting and related operations")[.](#thread.thread.id-7.sentence-1)
[8](#thread.thread.id-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1581)
*Returns*: strong_ordering::less if P(x, y) is true[.](#thread.thread.id-8.sentence-1)
Otherwise, strong_ordering::greater if P(y, x) is true[.](#thread.thread.id-8.sentence-2)
Otherwise, strong_ordering::equal[.](#thread.thread.id-8.sentence-3)
[🔗](#lib:operator%3c%3c,thread::id)
`template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& out, thread::id id);
`
[9](#thread.thread.id-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1597)
*Effects*: Inserts the text representation for charT of id intoout[.](#thread.thread.id-9.sentence-1)
[10](#thread.thread.id-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1602)
*Returns*: out[.](#thread.thread.id-10.sentence-1)
[🔗](#lib:formatter,specializations,thread::id)
`template<class charT> struct formatter<thread::id, charT>;
`
[11](#thread.thread.id-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1613)
formatter<thread::id, charT> interprets *format-spec* as a *thread-id-format-spec*[.](#thread.thread.id-11.sentence-1)
The syntax of format specifications is as follows:
thread-id-format-spec :
fill-and-alignopt widthopt
[*Note [2](#thread.thread.id-note-2)*:
The productions *fill-and-align* and *width* are described in [[format.string.std]](format.string.std "28.5.2.2Standard format specifiers")[.](#thread.thread.id-11.sentence-3)
— *end note*]
[12](#thread.thread.id-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1628)
If the *align* option is omitted it defaults to >[.](#thread.thread.id-12.sentence-1)
[13](#thread.thread.id-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1631)
A thread::id object is formatted by
writing its text representation for charT to the output
with additional padding and adjustments as specified by the format specifiers[.](#thread.thread.id-13.sentence-1)
[🔗](#lib:hash,thread::id)
`template<> struct hash<thread::id>;
`
[14](#thread.thread.id-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1643)
The specialization is enabled ([[unord.hash]](unord.hash "22.10.19Class template hash"))[.](#thread.thread.id-14.sentence-1)
#### [32.4.3.3](#thread.thread.constr) Constructors [[thread.thread.constr]](thread.thread.constr)
[🔗](#lib:thread,constructor)
`thread() noexcept;
`
[1](#thread.thread.constr-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1655)
*Effects*: The object does not represent a thread of execution[.](#thread.thread.constr-1.sentence-1)
[2](#thread.thread.constr-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1659)
*Postconditions*: get_id() == id()[.](#thread.thread.constr-2.sentence-1)
[🔗](#lib:thread,constructor_)
`template<class F, class... Args> explicit thread(F&& f, Args&&... args);
`
[3](#thread.thread.constr-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1670)
*Constraints*: remove_cvref_t<F> is not the same type as thread[.](#thread.thread.constr-3.sentence-1)
[4](#thread.thread.constr-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1674)
*Mandates*: The following are all true:
- [(4.1)](#thread.thread.constr-4.1)
is_constructible_v<decay_t<F>, F>,
- [(4.2)](#thread.thread.constr-4.2)
(is_constructible_v<decay_t<Args>, Args> && ...), and
- [(4.3)](#thread.thread.constr-4.3)
is_invocable_v<decay_t<F>, decay_t<Args>...>[.](#thread.thread.constr-4.sentence-1)
[5](#thread.thread.constr-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1683)
*Effects*: The new thread of execution executesinvoke(auto(std::forward<F>(f)), // for invoke, see [[func.invoke]](func.invoke "22.10.5invoke functions")auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion")) in the constructing thread[.](#thread.thread.constr-5.sentence-1)
Any return value from this invocation is ignored[.](#thread.thread.constr-5.sentence-2)
[*Note [1](#thread.thread.constr-note-1)*:
This implies that any exceptions not thrown from the invocation of the copy
of f will be thrown in the constructing thread, not the new thread[.](#thread.thread.constr-5.sentence-3)
— *end note*]
If the invocation of invoke terminates with an uncaught exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#thread.thread.constr-5.sentence-4)
[6](#thread.thread.constr-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1700)
*Synchronization*: The completion of the invocation of the constructor
synchronizes with the beginning of the invocation of the copy of f[.](#thread.thread.constr-6.sentence-1)
[7](#thread.thread.constr-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1705)
*Postconditions*: get_id() != id()[.](#thread.thread.constr-7.sentence-1)
*this represents the newly started thread[.](#thread.thread.constr-7.sentence-2)
[8](#thread.thread.constr-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1709)
*Throws*: system_error if unable to start the new thread[.](#thread.thread.constr-8.sentence-1)
[9](#thread.thread.constr-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1713)
*Error conditions*:
- [(9.1)](#thread.thread.constr-9.1)
resource_unavailable_try_again — the system lacked the necessary
resources to create another thread, or the system-imposed limit on the number of
threads in a process would be exceeded[.](#thread.thread.constr-9.sentence-1)
[🔗](#lib:thread,constructor__)
`thread(thread&& x) noexcept;
`
[10](#thread.thread.constr-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1728)
*Postconditions*: x.get_id() == id() and get_id() returns the
value of x.get_id() prior to the start of construction[.](#thread.thread.constr-10.sentence-1)
#### [32.4.3.4](#thread.thread.destr) Destructor [[thread.thread.destr]](thread.thread.destr)
[🔗](#lib:thread,destructor)
`~thread();
`
[1](#thread.thread.destr-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1742)
*Effects*: If joinable(), invokes terminate ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#thread.thread.destr-1.sentence-1)
Otherwise, has no effects[.](#thread.thread.destr-1.sentence-2)
[*Note [1](#thread.thread.destr-note-1)*:
Either implicitly detaching or joining a joinable() thread in its
destructor can result in difficult to debug correctness (for detach) or performance
(for join) bugs encountered only when an exception is thrown[.](#thread.thread.destr-1.sentence-3)
These bugs can be avoided by ensuring that
the destructor is never executed while the thread is still joinable[.](#thread.thread.destr-1.sentence-4)
— *end note*]
#### [32.4.3.5](#thread.thread.assign) Assignment [[thread.thread.assign]](thread.thread.assign)
[🔗](#lib:operator=,thread)
`thread& operator=(thread&& x) noexcept;
`
[1](#thread.thread.assign-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1763)
*Effects*: If joinable(), invokes terminate ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#thread.thread.assign-1.sentence-1)
Otherwise, assigns the
state of x to *this and sets x to a default constructed state[.](#thread.thread.assign-1.sentence-2)
[2](#thread.thread.assign-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1769)
*Postconditions*: x.get_id() == id() and get_id() returns the value ofx.get_id() prior to the assignment[.](#thread.thread.assign-2.sentence-1)
[3](#thread.thread.assign-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1774)
*Returns*: *this[.](#thread.thread.assign-3.sentence-1)
#### [32.4.3.6](#thread.thread.member) Members [[thread.thread.member]](thread.thread.member)
[🔗](#lib:swap,thread)
`void swap(thread& x) noexcept;
`
[1](#thread.thread.member-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1787)
*Effects*: Swaps the state of *this and x[.](#thread.thread.member-1.sentence-1)
[🔗](#lib:joinable,thread)
`bool joinable() const noexcept;
`
[2](#thread.thread.member-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1798)
*Returns*: get_id() != id()[.](#thread.thread.member-2.sentence-1)
[🔗](#lib:join,thread)
`void join();
`
[3](#thread.thread.member-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1809)
*Effects*: Blocks until the thread represented by *this has completed[.](#thread.thread.member-3.sentence-1)
[4](#thread.thread.member-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1814)
*Synchronization*: The completion of the thread represented by *this synchronizes with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
the corresponding successfuljoin() return[.](#thread.thread.member-4.sentence-1)
[*Note [1](#thread.thread.member-note-1)*:
Operations on*this are not synchronized[.](#thread.thread.member-4.sentence-2)
— *end note*]
[5](#thread.thread.member-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1824)
*Postconditions*: The thread represented by *this has completed[.](#thread.thread.member-5.sentence-1)
get_id() == id()[.](#thread.thread.member-5.sentence-2)
[6](#thread.thread.member-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1828)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.thread.member-6.sentence-1)
[7](#thread.thread.member-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1833)
*Error conditions*:
- [(7.1)](#thread.thread.member-7.1)
resource_deadlock_would_occur — if deadlock is detected orget_id() == this_thread::get_id()[.](#thread.thread.member-7.1.sentence-1)
- [(7.2)](#thread.thread.member-7.2)
no_such_process — if the thread is not valid[.](#thread.thread.member-7.2.sentence-1)
- [(7.3)](#thread.thread.member-7.3)
invalid_argument — if the thread is not joinable[.](#thread.thread.member-7.3.sentence-1)
[🔗](#lib:detach,thread)
`void detach();
`
[8](#thread.thread.member-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1851)
*Effects*: The thread represented by *this continues execution without the calling thread
blocking[.](#thread.thread.member-8.sentence-1)
When detach() returns, *this no longer represents the possibly continuing
thread of execution[.](#thread.thread.member-8.sentence-2)
When the thread previously represented by *this ends execution, the
implementation releases any owned resources[.](#thread.thread.member-8.sentence-3)
[9](#thread.thread.member-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1858)
*Postconditions*: get_id() == id()[.](#thread.thread.member-9.sentence-1)
[10](#thread.thread.member-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1862)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.thread.member-10.sentence-1)
[11](#thread.thread.member-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1867)
*Error conditions*:
- [(11.1)](#thread.thread.member-11.1)
no_such_process — if the thread is not valid[.](#thread.thread.member-11.1.sentence-1)
- [(11.2)](#thread.thread.member-11.2)
invalid_argument — if the thread is not joinable[.](#thread.thread.member-11.2.sentence-1)
[🔗](#lib:get_id,thread)
`id get_id() const noexcept;
`
[12](#thread.thread.member-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1881)
*Returns*: A default constructed id object if *this does not represent a thread,
otherwise this_thread::get_id() for the thread of execution represented by*this[.](#thread.thread.member-12.sentence-1)
#### [32.4.3.7](#thread.thread.static) Static members [[thread.thread.static]](thread.thread.static)
[🔗](#lib:hardware_concurrency,thread)
`unsigned hardware_concurrency() noexcept;
`
[1](#thread.thread.static-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1896)
*Returns*: The number of hardware thread contexts[.](#thread.thread.static-1.sentence-1)
[*Note [1](#thread.thread.static-note-1)*:
This value should
only be considered to be a hint[.](#thread.thread.static-1.sentence-2)
— *end note*]
If this value is not computable or
well-defined, an implementation should return 0[.](#thread.thread.static-1.sentence-3)
#### [32.4.3.8](#thread.thread.algorithm) Specialized algorithms [[thread.thread.algorithm]](thread.thread.algorithm)
[🔗](#lib:swap,thread_)
`void swap(thread& x, thread& y) noexcept;
`
[1](#thread.thread.algorithm-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1915)
*Effects*: As if by x.swap(y)[.](#thread.thread.algorithm-1.sentence-1)

View File

@@ -0,0 +1,46 @@
[thread.thread.class.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.class.general)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#general)
#### 32.4.3.1 General [thread.thread.class.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1443)
The class thread provides a mechanism to create a new thread of execution, to join with
a thread (i.e., wait for a thread to complete), and to perform other operations that manage and
query the state of a thread[.](#1.sentence-1)
A thread object uniquely represents a particular thread of
execution[.](#1.sentence-2)
That representation may be transferred to other thread objects in such a way
that no two thread objects simultaneously represent the same thread of execution[.](#1.sentence-3)
A
thread of execution is [*detached*](#def:detached) when no thread object represents that thread[.](#1.sentence-4)
Objects of class thread can be in a state that does not represent a thread of
execution[.](#1.sentence-5)
[*Note [1](#note-1)*:
A thread object does not represent a thread of execution after
default construction, after being moved from, or after a successful call to detach orjoin[.](#1.sentence-6)
— *end note*]
[🔗](#lib:thread)
namespace std {class thread {public:// [[thread.thread.id]](thread.thread.id "32.4.3.2Class thread::id"), class thread::idclass id; using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// construct/copy/destroy thread() noexcept; template<class F, class... Args> explicit thread(F&& f, Args&&... args); ~thread();
thread(const thread&) = delete;
thread(thread&&) noexcept;
thread& operator=(const thread&) = delete;
thread& operator=(thread&&) noexcept; // [[thread.thread.member]](thread.thread.member "32.4.3.6Members"), membersvoid swap(thread&) noexcept; bool joinable() const noexcept; void join(); void detach();
id get_id() const noexcept;
native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")// static membersstatic unsigned int hardware_concurrency() noexcept; };}

View File

@@ -0,0 +1,117 @@
[thread.thread.constr]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.constr)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.constr)
#### 32.4.3.3 Constructors [thread.thread.constr]
[🔗](#lib:thread,constructor)
`thread() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1655)
*Effects*: The object does not represent a thread of execution[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1659)
*Postconditions*: get_id() == id()[.](#2.sentence-1)
[🔗](#lib:thread,constructor_)
`template<class F, class... Args> explicit thread(F&& f, Args&&... args);
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1670)
*Constraints*: remove_cvref_t<F> is not the same type as thread[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1674)
*Mandates*: The following are all true:
- [(4.1)](#4.1)
is_constructible_v<decay_t<F>, F>,
- [(4.2)](#4.2)
(is_constructible_v<decay_t<Args>, Args> && ...), and
- [(4.3)](#4.3)
is_invocable_v<decay_t<F>, decay_t<Args>...>[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1683)
*Effects*: The new thread of execution executesinvoke(auto(std::forward<F>(f)), // for invoke, see [[func.invoke]](func.invoke "22.10.5invoke functions")auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion")) in the constructing thread[.](#5.sentence-1)
Any return value from this invocation is ignored[.](#5.sentence-2)
[*Note [1](#note-1)*:
This implies that any exceptions not thrown from the invocation of the copy
of f will be thrown in the constructing thread, not the new thread[.](#5.sentence-3)
— *end note*]
If the invocation of invoke terminates with an uncaught exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#5.sentence-4)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1700)
*Synchronization*: The completion of the invocation of the constructor
synchronizes with the beginning of the invocation of the copy of f[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1705)
*Postconditions*: get_id() != id()[.](#7.sentence-1)
*this represents the newly started thread[.](#7.sentence-2)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1709)
*Throws*: system_error if unable to start the new thread[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1713)
*Error conditions*:
- [(9.1)](#9.1)
resource_unavailable_try_again — the system lacked the necessary
resources to create another thread, or the system-imposed limit on the number of
threads in a process would be exceeded[.](#9.sentence-1)
[🔗](#lib:thread,constructor__)
`thread(thread&& x) noexcept;
`
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1728)
*Postconditions*: x.get_id() == id() and get_id() returns the
value of x.get_id() prior to the start of construction[.](#10.sentence-1)

View File

@@ -0,0 +1,33 @@
[thread.thread.destr]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.destr)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.destr)
#### 32.4.3.4 Destructor [thread.thread.destr]
[🔗](#lib:thread,destructor)
`~thread();
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1742)
*Effects*: If joinable(), invokes terminate ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#1.sentence-1)
Otherwise, has no effects[.](#1.sentence-2)
[*Note [1](#note-1)*:
Either implicitly detaching or joining a joinable() thread in its
destructor can result in difficult to debug correctness (for detach) or performance
(for join) bugs encountered only when an exception is thrown[.](#1.sentence-3)
These bugs can be avoided by ensuring that
the destructor is never executed while the thread is still joinable[.](#1.sentence-4)
— *end note*]

View File

@@ -0,0 +1,170 @@
[thread.thread.id]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.id)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.id)
#### 32.4.3.2 Class thread::id [thread.thread.id]
[🔗](#lib:thread::id)
namespace std {class thread::id {public: id() noexcept; }; bool operator==(thread::id x, thread::id y) noexcept;
strong_ordering operator<=>(thread::id x, thread::id y) noexcept; template<class charT, class traits> basic_ostream<charT, traits>&operator<<(basic_ostream<charT, traits>& out, thread::id id); template<class charT> struct formatter<thread::id, charT>; // hash supporttemplate<class T> struct hash; template<> struct hash<thread::id>;}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1516)
An object of type thread::id provides a unique identifier for
each thread of execution and a single distinct value for all thread objects that do not represent a thread of
execution ([[thread.thread.class]](thread.thread.class "32.4.3Class thread"))[.](#1.sentence-1)
Each thread of execution has an
associated thread::id object that is not equal to thethread::id object of any other thread of execution and that is not
equal to the thread::id object of any thread object that
does not represent threads of execution[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1526)
The [*text representation*](#def:text_representation "32.4.3.2Class thread::id[thread.thread.id]") for
the character type charT of an object of type thread::id is an unspecified sequence of charT such that,
for two objects of type thread::id x and y,
if x == y is true,
the thread::id objects have the same text representation, and
if x != y is true,
the thread::id objects have distinct text representations[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1536)
thread::id is a trivially copyable class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#3.sentence-1)
The library may reuse the value of a thread::id of a terminated thread that can no longer be joined[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1540)
[*Note [1](#note-1)*:
Relational operators allow thread::id objects to be used as
keys in associative containers[.](#4.sentence-1)
— *end note*]
[🔗](#lib:thread::id,constructor)
`id() noexcept;
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1552)
*Postconditions*: The constructed object does not represent a thread of execution[.](#5.sentence-1)
[🔗](#lib:operator==,thread::id)
`bool operator==(thread::id x, thread::id y) noexcept;
`
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1563)
*Returns*: true only if x and y represent the same
thread of execution or neither x nor y represents a thread of
execution[.](#6.sentence-1)
[🔗](#lib:operator%3c=%3e,thread::id)
`strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1576)
Let P(x, y) be
an unspecified total ordering over thread::id as described in [[alg.sorting]](alg.sorting "26.8Sorting and related operations")[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1581)
*Returns*: strong_ordering::less if P(x, y) is true[.](#8.sentence-1)
Otherwise, strong_ordering::greater if P(y, x) is true[.](#8.sentence-2)
Otherwise, strong_ordering::equal[.](#8.sentence-3)
[🔗](#lib:operator%3c%3c,thread::id)
`template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& out, thread::id id);
`
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1597)
*Effects*: Inserts the text representation for charT of id intoout[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1602)
*Returns*: out[.](#10.sentence-1)
[🔗](#lib:formatter,specializations,thread::id)
`template<class charT> struct formatter<thread::id, charT>;
`
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1613)
formatter<thread::id, charT> interprets *format-spec* as a *thread-id-format-spec*[.](#11.sentence-1)
The syntax of format specifications is as follows:
thread-id-format-spec :
fill-and-alignopt widthopt
[*Note [2](#note-2)*:
The productions *fill-and-align* and *width* are described in [[format.string.std]](format.string.std "28.5.2.2Standard format specifiers")[.](#11.sentence-3)
— *end note*]
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1628)
If the *align* option is omitted it defaults to >[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1631)
A thread::id object is formatted by
writing its text representation for charT to the output
with additional padding and adjustments as specified by the format specifiers[.](#13.sentence-1)
[🔗](#lib:hash,thread::id)
`template<> struct hash<thread::id>;
`
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1643)
The specialization is enabled ([[unord.hash]](unord.hash "22.10.19Class template hash"))[.](#14.sentence-1)

View File

@@ -0,0 +1,145 @@
[thread.thread.member]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.member)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.member)
#### 32.4.3.6 Members [thread.thread.member]
[🔗](#lib:swap,thread)
`void swap(thread& x) noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1787)
*Effects*: Swaps the state of *this and x[.](#1.sentence-1)
[🔗](#lib:joinable,thread)
`bool joinable() const noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1798)
*Returns*: get_id() != id()[.](#2.sentence-1)
[🔗](#lib:join,thread)
`void join();
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1809)
*Effects*: Blocks until the thread represented by *this has completed[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1814)
*Synchronization*: The completion of the thread represented by *this synchronizes with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
the corresponding successfuljoin() return[.](#4.sentence-1)
[*Note [1](#note-1)*:
Operations on*this are not synchronized[.](#4.sentence-2)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1824)
*Postconditions*: The thread represented by *this has completed[.](#5.sentence-1)
get_id() == id()[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1828)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1833)
*Error conditions*:
- [(7.1)](#7.1)
resource_deadlock_would_occur — if deadlock is detected orget_id() == this_thread::get_id()[.](#7.1.sentence-1)
- [(7.2)](#7.2)
no_such_process — if the thread is not valid[.](#7.2.sentence-1)
- [(7.3)](#7.3)
invalid_argument — if the thread is not joinable[.](#7.3.sentence-1)
[🔗](#lib:detach,thread)
`void detach();
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1851)
*Effects*: The thread represented by *this continues execution without the calling thread
blocking[.](#8.sentence-1)
When detach() returns, *this no longer represents the possibly continuing
thread of execution[.](#8.sentence-2)
When the thread previously represented by *this ends execution, the
implementation releases any owned resources[.](#8.sentence-3)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1858)
*Postconditions*: get_id() == id()[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1862)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1867)
*Error conditions*:
- [(11.1)](#11.1)
no_such_process — if the thread is not valid[.](#11.1.sentence-1)
- [(11.2)](#11.2)
invalid_argument — if the thread is not joinable[.](#11.2.sentence-1)
[🔗](#lib:get_id,thread)
`id get_id() const noexcept;
`
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1881)
*Returns*: A default constructed id object if *this does not represent a thread,
otherwise this_thread::get_id() for the thread of execution represented by*this[.](#12.sentence-1)

View File

@@ -0,0 +1,30 @@
[thread.thread.static]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.static)
### 32.4.3 Class thread [[thread.thread.class]](thread.thread.class#thread.thread.static)
#### 32.4.3.7 Static members [thread.thread.static]
[🔗](#lib:hardware_concurrency,thread)
`unsigned hardware_concurrency() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1896)
*Returns*: The number of hardware thread contexts[.](#1.sentence-1)
[*Note [1](#note-1)*:
This value should
only be considered to be a hint[.](#1.sentence-2)
— *end note*]
If this value is not computable or
well-defined, an implementation should return 0[.](#1.sentence-3)

View File

@@ -0,0 +1,92 @@
[thread.thread.this]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#thread.thread.this)
### 32.4.5 Namespace this_thread [thread.thread.this]
namespace std::this_thread { thread::id get_id() noexcept; void yield() noexcept; template<class Clock, class Duration>void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period>void sleep_for(const chrono::duration<Rep, Period>& rel_time);}
[🔗](#lib:get_id,this_thread)
`thread::id this_thread::get_id() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2316)
*Returns*: An object of type thread::id that uniquely identifies the current thread of execution[.](#1.sentence-1)
Every invocation from this thread of execution returns the same value[.](#1.sentence-2)
The object returned does not compare equal to
a default-constructed thread::id[.](#1.sentence-3)
[🔗](#lib:yield,this_thread)
`void this_thread::yield() noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2331)
*Effects*: Offers the implementation the opportunity to reschedule[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2335)
*Synchronization*: None[.](#3.sentence-1)
[🔗](#lib:sleep_until,this_thread)
`template<class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2347)
*Effects*: Blocks the calling thread for the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified
by abs_time[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2353)
*Synchronization*: None[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2357)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#6.sentence-1)
[🔗](#lib:sleep_for,this_thread)
`template<class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2369)
*Effects*: Blocks the calling thread for the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified
by rel_time[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2375)
*Synchronization*: None[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2379)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#9.sentence-1)

1049
cppdraft/thread/threads.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
[thread.threads.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.4 Threads [[thread.threads]](thread.threads#general)
### 32.4.1 General [thread.threads.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L1405)
[[thread.threads]](thread.threads "32.4Threads") describes components that can be used to create and manage threads[.](#1.sentence-1)
[*Note [1](#note-1)*:
These threads are intended to map one-to-one with operating system threads[.](#1.sentence-2)
— *end note*]

View File

@@ -0,0 +1,59 @@
[thread.timedmutex.class]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.timedmutex.class)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.timedmutex.class)
#### 32.6.4.3 Timed mutex types [[thread.timedmutex.requirements]](thread.timedmutex.requirements#thread.timedmutex.class)
#### 32.6.4.3.2 Class timed_mutex [thread.timedmutex.class]
[🔗](#lib:timed_mutex)
namespace std {class timed_mutex {public: timed_mutex(); ~timed_mutex();
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete; void lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7723)
The class timed_mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#1.sentence-1)
If one thread owns a timed_mutex object, attempts by another thread
to acquire ownership of that object will fail (for try_lock()) or block
(for lock(), try_lock_for(), and try_lock_until()) until
the owning thread has released ownership with a call to unlock() or the
call to try_lock_for() or try_lock_until() times out (having
failed to obtain ownership)[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7733)
The class timed_mutex meets
all of the timed mutex requirements ([[thread.timedmutex.requirements]](thread.timedmutex.requirements "32.6.4.3Timed mutex types"))[.](#2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7738)
The behavior of a program is undefined if
- [(3.1)](#3.1)
it destroys a timed_mutex object owned by any thread,
- [(3.2)](#3.2)
a thread that owns a timed_mutex object calls lock(),try_lock(), try_lock_for(), or try_lock_until() on that object, or
- [(3.3)](#3.3)
a thread terminates while owning a timed_mutex object[.](#3.sentence-1)

View File

@@ -0,0 +1,73 @@
[thread.timedmutex.recursive]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.timedmutex.recursive)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.timedmutex.recursive)
#### 32.6.4.3 Timed mutex types [[thread.timedmutex.requirements]](thread.timedmutex.requirements#thread.timedmutex.recursive)
#### 32.6.4.3.3 Class recursive_timed_mutex [thread.timedmutex.recursive]
[🔗](#lib:recursive_timed_mutex)
namespace std {class recursive_timed_mutex {public: recursive_timed_mutex(); ~recursive_timed_mutex();
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); // blockingbool try_lock() noexcept; template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7774)
The class recursive_timed_mutex provides a recursive mutex with exclusive
ownership semantics[.](#1.sentence-1)
If one thread owns a recursive_timed_mutex object,
attempts by another thread to acquire ownership of that object will fail (fortry_lock()) or block (for lock(), try_lock_for(), andtry_lock_until()) until the owning thread has completely released
ownership or the call to try_lock_for() or try_lock_until() times out (having failed to obtain ownership)[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7784)
The class recursive_timed_mutex meets
all of the timed mutex requirements ([[thread.timedmutex.requirements]](thread.timedmutex.requirements "32.6.4.3Timed mutex types"))[.](#2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7789)
A thread that owns a recursive_timed_mutex object may acquire additional
levels of ownership by calling lock(), try_lock(),try_lock_for(), or try_lock_until() on that object[.](#3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#3.sentence-2)
If
a thread has already acquired the maximum level of ownership for arecursive_timed_mutex object, additional calls to try_lock(),try_lock_for(), or try_lock_until() fail, and additional
calls to lock() throw an exception of type system_error[.](#3.sentence-3)
A
thread shall call unlock() once for each level of ownership acquired by
calls to lock(), try_lock(), try_lock_for(), andtry_lock_until()[.](#3.sentence-4)
Only when all levels of ownership have been released
may ownership of the object be acquired by another thread[.](#3.sentence-5)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7803)
The behavior of a program is undefined if
- [(4.1)](#4.1)
it destroys a recursive_timed_mutex object owned by any thread, or
- [(4.2)](#4.2)
a thread terminates while owning a recursive_timed_mutex object[.](#4.sentence-1)

View File

@@ -0,0 +1,264 @@
[thread.timedmutex.requirements]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.timedmutex.requirements)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.timedmutex.requirements)
#### 32.6.4.3 Timed mutex types [thread.timedmutex.requirements]
#### [32.6.4.3.1](#general) General [[thread.timedmutex.requirements.general]](thread.timedmutex.requirements.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7600)
The [*timed mutex types*](#def:timed_mutex_types "32.6.4.3.1General[thread.timedmutex.requirements.general]") are the standard library types timed_mutex,recursive_timed_mutex, and shared_timed_mutex[.](#general-1.sentence-1)
They
meet the requirements set out below[.](#general-1.sentence-2)
In this description, m denotes an object of a mutex type,rel_time denotes an object of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes an
object of an
instantiation of [time_point](time.point "30.6Class template time_­point[time.point]")[.](#general-1.sentence-3)
[*Note [1](#general-note-1)*:
The timed mutex types meet the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#general-1.sentence-4)
— *end note*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7614)
The expression m.try_lock_for(rel_time) is well-formed
and has the following semantics:
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7618)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not
own the mutex[.](#general-3.sentence-1)
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7624)
*Effects*: The function attempts to obtain ownership of the mutex within the
relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by rel_time[.](#general-4.sentence-1)
If the time specified by rel_time is less than or
equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by callingtry_lock())[.](#general-4.sentence-2)
The function returns within the timeout specified byrel_time only if it has obtained ownership of the mutex object[.](#general-4.sentence-3)
[*Note [2](#general-note-2)*:
As
with try_lock(), there is no guarantee that ownership will be obtained if the
lock is available, but implementations are expected to make a strong effort to do so[.](#general-4.sentence-4)
— *end note*]
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7638)
*Synchronization*: If try_lock_for() returns true, prior unlock() operations
on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#general-5.sentence-1)
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7643)
*Return type*: bool[.](#general-6.sentence-1)
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7646)
*Returns*: true if ownership was obtained, otherwise false[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7650)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#general-8.sentence-1)
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7655)
The expression m.try_lock_until(abs_time) is well-formed
and has the following semantics:
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7659)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not own the
mutex[.](#general-10.sentence-1)
[11](#general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7665)
*Effects*: The function attempts to obtain ownership of the mutex[.](#general-11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain ownership
without blocking (as if by calling try_lock())[.](#general-11.sentence-2)
The function
returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified byabs_time only if it has obtained ownership of the mutex object[.](#general-11.sentence-3)
[*Note [3](#general-note-3)*:
As with try_lock(), there is no guarantee that ownership will
be obtained if the lock is available, but implementations are expected to make a
strong effort to do so[.](#general-11.sentence-4)
— *end note*]
[12](#general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7678)
*Synchronization*: If try_lock_until() returns true, prior unlock() operations on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
this operation[.](#general-12.sentence-1)
[13](#general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7684)
*Return type*: bool[.](#general-13.sentence-1)
[14](#general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7687)
*Returns*: true if ownership was obtained, otherwise false[.](#general-14.sentence-1)
[15](#general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7691)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#general-15.sentence-1)
#### [32.6.4.3.2](#thread.timedmutex.class) Class timed_mutex [[thread.timedmutex.class]](thread.timedmutex.class)
[🔗](#lib:timed_mutex)
namespace std {class timed_mutex {public: timed_mutex(); ~timed_mutex();
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete; void lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.timedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7723)
The class timed_mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#thread.timedmutex.class-1.sentence-1)
If one thread owns a timed_mutex object, attempts by another thread
to acquire ownership of that object will fail (for try_lock()) or block
(for lock(), try_lock_for(), and try_lock_until()) until
the owning thread has released ownership with a call to unlock() or the
call to try_lock_for() or try_lock_until() times out (having
failed to obtain ownership)[.](#thread.timedmutex.class-1.sentence-2)
[2](#thread.timedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7733)
The class timed_mutex meets
all of the timed mutex requirements ([thread.timedmutex.requirements])[.](#thread.timedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.timedmutex.class-2.sentence-2)
[3](#thread.timedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7738)
The behavior of a program is undefined if
- [(3.1)](#thread.timedmutex.class-3.1)
it destroys a timed_mutex object owned by any thread,
- [(3.2)](#thread.timedmutex.class-3.2)
a thread that owns a timed_mutex object calls lock(),try_lock(), try_lock_for(), or try_lock_until() on that object, or
- [(3.3)](#thread.timedmutex.class-3.3)
a thread terminates while owning a timed_mutex object[.](#thread.timedmutex.class-3.sentence-1)
#### [32.6.4.3.3](#thread.timedmutex.recursive) Class recursive_timed_mutex [[thread.timedmutex.recursive]](thread.timedmutex.recursive)
[🔗](#lib:recursive_timed_mutex)
namespace std {class recursive_timed_mutex {public: recursive_timed_mutex(); ~recursive_timed_mutex();
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); // blockingbool try_lock() noexcept; template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.timedmutex.recursive-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7774)
The class recursive_timed_mutex provides a recursive mutex with exclusive
ownership semantics[.](#thread.timedmutex.recursive-1.sentence-1)
If one thread owns a recursive_timed_mutex object,
attempts by another thread to acquire ownership of that object will fail (fortry_lock()) or block (for lock(), try_lock_for(), andtry_lock_until()) until the owning thread has completely released
ownership or the call to try_lock_for() or try_lock_until() times out (having failed to obtain ownership)[.](#thread.timedmutex.recursive-1.sentence-2)
[2](#thread.timedmutex.recursive-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7784)
The class recursive_timed_mutex meets
all of the timed mutex requirements ([thread.timedmutex.requirements])[.](#thread.timedmutex.recursive-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.timedmutex.recursive-2.sentence-2)
[3](#thread.timedmutex.recursive-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7789)
A thread that owns a recursive_timed_mutex object may acquire additional
levels of ownership by calling lock(), try_lock(),try_lock_for(), or try_lock_until() on that object[.](#thread.timedmutex.recursive-3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#thread.timedmutex.recursive-3.sentence-2)
If
a thread has already acquired the maximum level of ownership for arecursive_timed_mutex object, additional calls to try_lock(),try_lock_for(), or try_lock_until() fail, and additional
calls to lock() throw an exception of type system_error[.](#thread.timedmutex.recursive-3.sentence-3)
A
thread shall call unlock() once for each level of ownership acquired by
calls to lock(), try_lock(), try_lock_for(), andtry_lock_until()[.](#thread.timedmutex.recursive-3.sentence-4)
Only when all levels of ownership have been released
may ownership of the object be acquired by another thread[.](#thread.timedmutex.recursive-3.sentence-5)
[4](#thread.timedmutex.recursive-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7803)
The behavior of a program is undefined if
- [(4.1)](#thread.timedmutex.recursive-4.1)
it destroys a recursive_timed_mutex object owned by any thread, or
- [(4.2)](#thread.timedmutex.recursive-4.2)
a thread terminates while owning a recursive_timed_mutex object[.](#thread.timedmutex.recursive-4.sentence-1)

View File

@@ -0,0 +1,150 @@
[thread.timedmutex.requirements.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#thread.timedmutex.requirements.general)
### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#thread.timedmutex.requirements.general)
#### 32.6.4.3 Timed mutex types [[thread.timedmutex.requirements]](thread.timedmutex.requirements#general)
#### 32.6.4.3.1 General [thread.timedmutex.requirements.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7600)
The [*timed mutex types*](#def:timed_mutex_types "32.6.4.3.1General[thread.timedmutex.requirements.general]") are the standard library types timed_mutex,recursive_timed_mutex, and shared_timed_mutex[.](#1.sentence-1)
They
meet the requirements set out below[.](#1.sentence-2)
In this description, m denotes an object of a mutex type,rel_time denotes an object of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes an
object of an
instantiation of [time_point](time.point "30.6Class template time_­point[time.point]")[.](#1.sentence-3)
[*Note [1](#note-1)*:
The timed mutex types meet the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#1.sentence-4)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7614)
The expression m.try_lock_for(rel_time) is well-formed
and has the following semantics:
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7618)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not
own the mutex[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7624)
*Effects*: The function attempts to obtain ownership of the mutex within the
relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by rel_time[.](#4.sentence-1)
If the time specified by rel_time is less than or
equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by callingtry_lock())[.](#4.sentence-2)
The function returns within the timeout specified byrel_time only if it has obtained ownership of the mutex object[.](#4.sentence-3)
[*Note [2](#note-2)*:
As
with try_lock(), there is no guarantee that ownership will be obtained if the
lock is available, but implementations are expected to make a strong effort to do so[.](#4.sentence-4)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7638)
*Synchronization*: If try_lock_for() returns true, prior unlock() operations
on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7643)
*Return type*: bool[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7646)
*Returns*: true if ownership was obtained, otherwise false[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7650)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7655)
The expression m.try_lock_until(abs_time) is well-formed
and has the following semantics:
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7659)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not own the
mutex[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7665)
*Effects*: The function attempts to obtain ownership of the mutex[.](#11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain ownership
without blocking (as if by calling try_lock())[.](#11.sentence-2)
The function
returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified byabs_time only if it has obtained ownership of the mutex object[.](#11.sentence-3)
[*Note [3](#note-3)*:
As with try_lock(), there is no guarantee that ownership will
be obtained if the lock is available, but implementations are expected to make a
strong effort to do so[.](#11.sentence-4)
— *end note*]
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7678)
*Synchronization*: If try_lock_until() returns true, prior unlock() operations on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
this operation[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7684)
*Return type*: bool[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7687)
*Returns*: true if ownership was obtained, otherwise false[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7691)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#15.sentence-1)