Init
This commit is contained in:
334
cppdraft/thread/barrier.md
Normal file
334
cppdraft/thread/barrier.md
Normal 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.3 Class 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.3 Class 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.3 Class 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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*]
|
||||
310
cppdraft/thread/barrier/class.md
Normal file
310
cppdraft/thread/barrier/class.md
Normal 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.3 Class 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.3 Class 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.3 Class 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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*]
|
||||
25
cppdraft/thread/barrier/general.md
Normal file
25
cppdraft/thread/barrier/general.md
Normal 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
1067
cppdraft/thread/condition.md
Normal file
File diff suppressed because it is too large
Load Diff
484
cppdraft/thread/condition/condvar.md
Normal file
484
cppdraft/thread/condition/condvar.md
Normal file
@@ -0,0 +1,484 @@
|
||||
[thread.condition.condvar]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvar)
|
||||
|
||||
### 32.7.4 Class condition_variable [thread.condition.condvar]
|
||||
|
||||
[ð](#lib:condition_variable)
|
||||
|
||||
namespace std {class condition_variable {public: condition_variable(); ~condition_variable();
|
||||
|
||||
condition_variable(const condition_variable&) = delete;
|
||||
condition_variable& operator=(const condition_variable&) = delete; void notify_one() noexcept; void notify_all() noexcept; void wait(unique_lock<mutex>& lock); template<class Predicate>void wait(unique_lock<mutex>& lock, Predicate pred); template<class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Clock, class Duration, class Predicate>bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred); template<class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time); template<class Rep, class Period, class Predicate>bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time,
|
||||
Predicate pred); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9618)
|
||||
|
||||
The class condition_variable is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable,constructor)
|
||||
|
||||
`condition_variable();
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9627)
|
||||
|
||||
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9631)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
resource_unavailable_try_again â if some non-memory resource
|
||||
limitation prevents initialization[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable,destructor)
|
||||
|
||||
`~condition_variable();
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9645)
|
||||
|
||||
*Preconditions*: There is no thread blocked on *this[.](#4.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
That is, all
|
||||
threads have been notified; they can subsequently block on the lock specified in the
|
||||
wait[.](#4.sentence-2)
|
||||
|
||||
This relaxes the usual rules, which would have required all wait calls to happen before
|
||||
destruction[.](#4.sentence-3)
|
||||
|
||||
Only the notification to unblock the wait needs to happen before destruction[.](#4.sentence-4)
|
||||
|
||||
Undefined behavior ensues if a thread waits on *this once the destructor has
|
||||
been started, especially when the waiting threads are calling the wait functions in a loop or
|
||||
using the overloads of wait, wait_for, or wait_until that take a predicate[.](#4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:notify_one,condition_variable)
|
||||
|
||||
`void notify_one() noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9666)
|
||||
|
||||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#5.sentence-1)
|
||||
|
||||
[ð](#lib:notify_all,condition_variable)
|
||||
|
||||
`void notify_all() noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9677)
|
||||
|
||||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:wait,condition_variable)
|
||||
|
||||
`void wait(unique_lock<mutex>& lock);
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9688)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9699)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#8.1.sentence-1)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns[.](#8.2.sentence-1)
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
The function will unblock when signaled by a call to notify_one() or a call to notify_all(), or spuriously[.](#8.3.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9709)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9714)
|
||||
|
||||
*Throws*: Nothing[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9718)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#11.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#11.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait,condition_variable_)
|
||||
|
||||
`template<class Predicate>
|
||||
void wait(unique_lock<mutex>& lock, Predicate pred);
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9734)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is
|
||||
locked by the calling thread, and either
|
||||
|
||||
- [(12.1)](#12.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(12.2)](#12.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#12.sentence-1)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9745)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred()) wait(lock);
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9753)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#14.sentence-1)
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9758)
|
||||
|
||||
*Throws*: Any exception thrown by pred[.](#15.sentence-1)
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9762)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#16.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#16.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_until,condition_variable)
|
||||
|
||||
`template<class Clock, class Duration>
|
||||
cv_status wait_until(unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& abs_time);
|
||||
`
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9779)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||||
|
||||
- [(17.1)](#17.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(17.2)](#17.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#17.sentence-1)
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9790)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(18.1)](#18.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#18.1.sentence-1)
|
||||
|
||||
- [(18.2)](#18.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns[.](#18.2.sentence-1)
|
||||
|
||||
- [(18.3)](#18.3)
|
||||
|
||||
The function will unblock when signaled by a call to notify_one(), a call to notify_all(),
|
||||
expiration of the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time,
|
||||
or spuriously[.](#18.3.sentence-1)
|
||||
|
||||
- [(18.4)](#18.4)
|
||||
|
||||
If the function exits via an exception, lock.lock() is called prior to exiting the function[.](#18.4.sentence-1)
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9808)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#19.sentence-1)
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9813)
|
||||
|
||||
*Returns*: cv_status::timeout if
|
||||
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time expired,
|
||||
otherwise cv_status::no_timeout[.](#20.sentence-1)
|
||||
|
||||
[21](#21)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9819)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#21.sentence-1)
|
||||
|
||||
[22](#22)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9824)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#22.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#22.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable)
|
||||
|
||||
`template<class Rep, class Period>
|
||||
cv_status wait_for(unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& rel_time);
|
||||
`
|
||||
|
||||
[23](#23)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9841)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||||
|
||||
- [(23.1)](#23.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(23.2)](#23.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments
|
||||
supplied by all concurrently waiting (via wait, wait_for, orwait_until) threads[.](#23.sentence-1)
|
||||
|
||||
[24](#24)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9852)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time);
|
||||
|
||||
[25](#25)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9859)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#25.sentence-1)
|
||||
|
||||
[26](#26)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9864)
|
||||
|
||||
*Returns*: cv_status::timeout if
|
||||
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by rel_time expired,
|
||||
otherwise cv_status::no_timeout[.](#26.sentence-1)
|
||||
|
||||
[27](#27)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9870)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#27.sentence-1)
|
||||
|
||||
[28](#28)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9875)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#28.sentence-1)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#28.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_until,condition_variable_)
|
||||
|
||||
`template<class Clock, class Duration, class Predicate>
|
||||
bool wait_until(unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred);
|
||||
`
|
||||
|
||||
[29](#29)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9893)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is
|
||||
locked by the calling thread, and either
|
||||
|
||||
- [(29.1)](#29.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(29.2)](#29.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait,wait_for, or wait_until) threads[.](#29.sentence-1)
|
||||
|
||||
[30](#30)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9904)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred())if (wait_until(lock, abs_time) == cv_status::timeout)return pred();return true;
|
||||
|
||||
[31](#31)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9914)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#31.sentence-1)
|
||||
|
||||
[32](#32)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9919)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluated totrue regardless of whether the timeout was triggered[.](#32.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[33](#33)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9925)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) or any exception thrown by pred[.](#33.sentence-1)
|
||||
|
||||
[34](#34)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9930)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#34.sentence-1)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#34.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable_)
|
||||
|
||||
`template<class Rep, class Period, class Predicate>
|
||||
bool wait_for(unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& rel_time,
|
||||
Predicate pred);
|
||||
`
|
||||
|
||||
[35](#35)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9948)
|
||||
|
||||
*Preconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
|
||||
|
||||
- [(35.1)](#35.1)
|
||||
|
||||
no other thread is waiting on this condition_variable object or
|
||||
|
||||
- [(35.2)](#35.2)
|
||||
|
||||
lock.mutex() returns the same value for each of the lock arguments
|
||||
supplied by all concurrently waiting (via wait, wait_for, orwait_until) threads[.](#35.sentence-1)
|
||||
|
||||
[36](#36)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9962)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||
|
||||
[37](#37)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9969)
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
There is no blocking if pred() is initially true, even if the
|
||||
timeout has already expired[.](#37.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[38](#38)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9975)
|
||||
|
||||
*Postconditions*: lock.owns_lock() is true and lock.mutex() is locked by the calling thread[.](#38.sentence-1)
|
||||
|
||||
[39](#39)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9980)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered[.](#39.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[40](#40)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9986)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) or any exception thrown by pred[.](#40.sentence-1)
|
||||
|
||||
[41](#41)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9991)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#41.sentence-1)
|
||||
|
||||
[*Note [10](#note-10)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#41.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
462
cppdraft/thread/condition/condvarany.md
Normal file
462
cppdraft/thread/condition/condvarany.md
Normal file
@@ -0,0 +1,462 @@
|
||||
[thread.condition.condvarany]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvarany)
|
||||
|
||||
### 32.7.5 Class condition_variable_any [thread.condition.condvarany]
|
||||
|
||||
#### [32.7.5.1](#general) General [[thread.condition.condvarany.general]](thread.condition.condvarany.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10004)
|
||||
|
||||
In [thread.condition.condvarany],
|
||||
template arguments for template parameters named Lock shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#general-1.sentence-1)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
All of the standard
|
||||
mutex types meet this requirement[.](#general-1.sentence-2)
|
||||
|
||||
If a type other than one of the
|
||||
standard mutex types or a unique_lock wrapper for a standard mutex type
|
||||
is used with condition_variable_any, any
|
||||
necessary synchronization is assumed to be in place with respect to the predicate associated
|
||||
with the condition_variable_any instance[.](#general-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:condition_variable_any)
|
||||
|
||||
namespace std {class condition_variable_any {public: condition_variable_any(); ~condition_variable_any();
|
||||
|
||||
condition_variable_any(const condition_variable_any&) = delete;
|
||||
condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; // [[thread.condvarany.wait]](#thread.condvarany.wait "32.7.5.2 Noninterruptible waits"), noninterruptible waitstemplate<class Lock>void wait(Lock& lock); template<class Lock, class Predicate>void wait(Lock& lock, Predicate pred); template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred); template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); // [[thread.condvarany.intwait]](#thread.condvarany.intwait "32.7.5.3 Interruptible waits"), interruptible waitstemplate<class Lock, class Predicate>bool wait(Lock& lock, stop_token stoken, Predicate pred); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred); };}
|
||||
|
||||
[ð](#lib:condition_variable_any,constructor)
|
||||
|
||||
`condition_variable_any();
|
||||
`
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10067)
|
||||
|
||||
*Throws*: bad_alloc or system_error when an exception is
|
||||
required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#general-2.sentence-1)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10072)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(3.1)](#general-3.1)
|
||||
|
||||
resource_unavailable_try_again â if some non-memory resource
|
||||
limitation prevents initialization[.](#general-3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#general-3.2)
|
||||
|
||||
operation_not_permitted â if the thread does not have the
|
||||
privilege to perform the operation[.](#general-3.2.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable_any,destructor)
|
||||
|
||||
`~condition_variable_any();
|
||||
`
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10089)
|
||||
|
||||
*Preconditions*: There is no thread blocked on *this[.](#general-4.sentence-1)
|
||||
|
||||
[*Note [2](#general-note-2)*:
|
||||
|
||||
That is, all
|
||||
threads have been notified; they can subsequently block on the lock specified in the
|
||||
wait[.](#general-4.sentence-2)
|
||||
|
||||
This relaxes the usual rules, which would have required all wait calls to happen before
|
||||
destruction[.](#general-4.sentence-3)
|
||||
|
||||
Only the notification to unblock the wait needs to happen before destruction[.](#general-4.sentence-4)
|
||||
|
||||
Undefined behavior ensues if a thread waits on *this once the destructor has
|
||||
been started, especially when the waiting threads are calling the wait functions in a loop or
|
||||
using the overloads of wait, wait_for, or wait_until that take a predicate[.](#general-4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:notify_one,condition_variable_any)
|
||||
|
||||
`void notify_one() noexcept;
|
||||
`
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10110)
|
||||
|
||||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#general-5.sentence-1)
|
||||
|
||||
[ð](#lib:notify_all,condition_variable_any)
|
||||
|
||||
`void notify_all() noexcept;
|
||||
`
|
||||
|
||||
[6](#general-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10121)
|
||||
|
||||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#general-6.sentence-1)
|
||||
|
||||
#### [32.7.5.2](#thread.condvarany.wait) Noninterruptible waits [[thread.condvarany.wait]](thread.condvarany.wait)
|
||||
|
||||
[ð](#lib:wait,condition_variable_any)
|
||||
|
||||
`template<class Lock>
|
||||
void wait(Lock& lock);
|
||||
`
|
||||
|
||||
[1](#thread.condvarany.wait-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10135)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(1.1)](#thread.condvarany.wait-1.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#thread.condvarany.wait-1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#thread.condvarany.wait-1.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#thread.condvarany.wait-1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#thread.condvarany.wait-1.3)
|
||||
|
||||
The function will unblock when signaled by a call to notify_one(),
|
||||
a call to notify_all(), or spuriously[.](#thread.condvarany.wait-1.3.sentence-1)
|
||||
|
||||
[2](#thread.condvarany.wait-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10145)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-2.sentence-1)
|
||||
|
||||
[3](#thread.condvarany.wait-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10149)
|
||||
|
||||
*Throws*: Nothing[.](#thread.condvarany.wait-3.sentence-1)
|
||||
|
||||
[4](#thread.condvarany.wait-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10153)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-4.sentence-1)
|
||||
|
||||
[*Note [1](#thread.condvarany.wait-note-1)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Predicate>
|
||||
void wait(Lock& lock, Predicate pred);
|
||||
`
|
||||
|
||||
[5](#thread.condvarany.wait-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10169)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred()) wait(lock);
|
||||
|
||||
[ð](#lib:wait_until,condition_variable_any)
|
||||
|
||||
`template<class Lock, class Clock, class Duration>
|
||||
cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
|
||||
`
|
||||
|
||||
[6](#thread.condvarany.wait-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10185)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(6.1)](#thread.condvarany.wait-6.1)
|
||||
|
||||
Atomically calls lock.unlock() and blocks on *this[.](#thread.condvarany.wait-6.1.sentence-1)
|
||||
|
||||
- [(6.2)](#thread.condvarany.wait-6.2)
|
||||
|
||||
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns[.](#thread.condvarany.wait-6.2.sentence-1)
|
||||
|
||||
- [(6.3)](#thread.condvarany.wait-6.3)
|
||||
|
||||
The function will unblock when signaled by a call to notify_one(), a call to notify_all(),
|
||||
expiration of the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time,
|
||||
or spuriously[.](#thread.condvarany.wait-6.3.sentence-1)
|
||||
|
||||
- [(6.4)](#thread.condvarany.wait-6.4)
|
||||
|
||||
If the function exits via an exception, lock.lock() is called prior to exiting the function[.](#thread.condvarany.wait-6.4.sentence-1)
|
||||
|
||||
[7](#thread.condvarany.wait-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10204)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-7.sentence-1)
|
||||
|
||||
[8](#thread.condvarany.wait-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10208)
|
||||
|
||||
*Returns*: cv_status::timeout if
|
||||
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time expired,
|
||||
otherwise cv_status::no_timeout[.](#thread.condvarany.wait-8.sentence-1)
|
||||
|
||||
[9](#thread.condvarany.wait-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10214)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#thread.condvarany.wait-9.sentence-1)
|
||||
|
||||
[10](#thread.condvarany.wait-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10219)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate() is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-10.sentence-1)
|
||||
|
||||
[*Note [2](#thread.condvarany.wait-note-2)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable_any)
|
||||
|
||||
`template<class Lock, class Rep, class Period>
|
||||
cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
|
||||
`
|
||||
|
||||
[11](#thread.condvarany.wait-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10235)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time);
|
||||
|
||||
[12](#thread.condvarany.wait-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10242)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.wait-12.sentence-1)
|
||||
|
||||
[13](#thread.condvarany.wait-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10246)
|
||||
|
||||
*Returns*: cv_status::timeout if
|
||||
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by rel_time expired,
|
||||
otherwise cv_status::no_timeout[.](#thread.condvarany.wait-13.sentence-1)
|
||||
|
||||
[14](#thread.condvarany.wait-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10252)
|
||||
|
||||
*Throws*: Timeout-related
|
||||
exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#thread.condvarany.wait-14.sentence-1)
|
||||
|
||||
[15](#thread.condvarany.wait-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10257)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition, terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.wait-15.sentence-1)
|
||||
|
||||
[*Note [3](#thread.condvarany.wait-note-3)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.wait-15.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_until,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
|
||||
`
|
||||
|
||||
[16](#thread.condvarany.wait-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10273)
|
||||
|
||||
*Effects*: Equivalent to:while (!pred())if (wait_until(lock, abs_time) == cv_status::timeout)return pred();return true;
|
||||
|
||||
[17](#thread.condvarany.wait-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10283)
|
||||
|
||||
[*Note [4](#thread.condvarany.wait-note-4)*:
|
||||
|
||||
There is no blocking if pred() is initially true, or
|
||||
if the timeout has already expired[.](#thread.condvarany.wait-17.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#thread.condvarany.wait-18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10289)
|
||||
|
||||
[*Note [5](#thread.condvarany.wait-note-5)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered[.](#thread.condvarany.wait-18.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:wait_for,condition_variable_any_)
|
||||
|
||||
`template<class Lock, class Rep, class Period, class Predicate>
|
||||
bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
|
||||
`
|
||||
|
||||
[19](#thread.condvarany.wait-19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10303)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||
|
||||
#### [32.7.5.3](#thread.condvarany.intwait) Interruptible waits [[thread.condvarany.intwait]](thread.condvarany.intwait)
|
||||
|
||||
[1](#thread.condvarany.intwait-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10313)
|
||||
|
||||
The following wait functions will be notified
|
||||
when there is a stop request on the passed stop_token[.](#thread.condvarany.intwait-1.sentence-1)
|
||||
|
||||
In that case the functions return immediately,
|
||||
returning false if the predicate evaluates to false[.](#thread.condvarany.intwait-1.sentence-2)
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:1)
|
||||
|
||||
`template<class Lock, class Predicate>
|
||||
bool wait(Lock& lock, stop_token stoken, Predicate pred);
|
||||
`
|
||||
|
||||
[2](#thread.condvarany.intwait-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10325)
|
||||
|
||||
*Effects*: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to:while (!stoken.stop_requested()) {if (pred())return true;
|
||||
wait(lock);}return pred();
|
||||
|
||||
[3](#thread.condvarany.intwait-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10339)
|
||||
|
||||
[*Note [1](#thread.condvarany.intwait-note-1)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluated totrue regardless of whether there was a stop request[.](#thread.condvarany.intwait-3.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#thread.condvarany.intwait-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10345)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.intwait-4.sentence-1)
|
||||
|
||||
[5](#thread.condvarany.intwait-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10349)
|
||||
|
||||
*Throws*: Any exception thrown by pred[.](#thread.condvarany.intwait-5.sentence-1)
|
||||
|
||||
[6](#thread.condvarany.intwait-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10353)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition,terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.intwait-6.sentence-1)
|
||||
|
||||
[*Note [2](#thread.condvarany.intwait-note-2)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.intwait-6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:2)
|
||||
|
||||
`template<class Lock, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(Lock& lock, stop_token stoken,
|
||||
const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
|
||||
`
|
||||
|
||||
[7](#thread.condvarany.intwait-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10369)
|
||||
|
||||
*Effects*: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to:while (!stoken.stop_requested()) {if (pred())return true; if (wait_until(lock, abs_time) == cv_status::timeout)return pred();}return pred();
|
||||
|
||||
[8](#thread.condvarany.intwait-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10384)
|
||||
|
||||
[*Note [3](#thread.condvarany.intwait-note-3)*:
|
||||
|
||||
There is no blocking if pred() is initially true,stoken.stop_requested() was already true or the timeout has already expired[.](#thread.condvarany.intwait-8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#thread.condvarany.intwait-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10391)
|
||||
|
||||
[*Note [4](#thread.condvarany.intwait-note-4)*:
|
||||
|
||||
The returned value indicates whether the predicate evaluated to true regardless of whether the timeout was triggered or a stop request was made[.](#thread.condvarany.intwait-9.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#thread.condvarany.intwait-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10397)
|
||||
|
||||
*Postconditions*: lock is locked by the calling thread[.](#thread.condvarany.intwait-10.sentence-1)
|
||||
|
||||
[11](#thread.condvarany.intwait-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10401)
|
||||
|
||||
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")),
|
||||
or any exception thrown by pred[.](#thread.condvarany.intwait-11.sentence-1)
|
||||
|
||||
[12](#thread.condvarany.intwait-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10406)
|
||||
|
||||
*Remarks*: If the function fails to meet the postcondition,terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#thread.condvarany.intwait-12.sentence-1)
|
||||
|
||||
[*Note [5](#thread.condvarany.intwait-note-5)*:
|
||||
|
||||
This can happen if the re-locking of the mutex throws an exception[.](#thread.condvarany.intwait-12.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#thread.condvarany.intwait-itemdecl:3)
|
||||
|
||||
`template<class Lock, class Rep, class Period, class Predicate>
|
||||
bool wait_for(Lock& lock, stop_token stoken,
|
||||
const chrono::duration<Rep, Period>& rel_time, Predicate pred);
|
||||
`
|
||||
|
||||
[13](#thread.condvarany.intwait-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10422)
|
||||
|
||||
*Effects*: Equivalent to:return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time,
|
||||
std::move(pred));
|
||||
115
cppdraft/thread/condition/condvarany/general.md
Normal file
115
cppdraft/thread/condition/condvarany/general.md
Normal file
@@ -0,0 +1,115 @@
|
||||
[thread.condition.condvarany.general]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#condvarany.general)
|
||||
|
||||
### 32.7.5 Class condition_variable_any [[thread.condition.condvarany]](thread.condition.condvarany#general)
|
||||
|
||||
#### 32.7.5.1 General [thread.condition.condvarany.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10004)
|
||||
|
||||
In [[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_variable_any"),
|
||||
template arguments for template parameters named Lock shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
All of the standard
|
||||
mutex types meet this requirement[.](#1.sentence-2)
|
||||
|
||||
If a type other than one of the
|
||||
standard mutex types or a unique_lock wrapper for a standard mutex type
|
||||
is used with condition_variable_any, any
|
||||
necessary synchronization is assumed to be in place with respect to the predicate associated
|
||||
with the condition_variable_any instance[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:condition_variable_any)
|
||||
|
||||
namespace std {class condition_variable_any {public: condition_variable_any(); ~condition_variable_any();
|
||||
|
||||
condition_variable_any(const condition_variable_any&) = delete;
|
||||
condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; // [[thread.condvarany.wait]](thread.condvarany.wait "32.7.5.2 Noninterruptible waits"), noninterruptible waitstemplate<class Lock>void wait(Lock& lock); template<class Lock, class Predicate>void wait(Lock& lock, Predicate pred); template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
|
||||
Predicate pred); template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); // [[thread.condvarany.intwait]](thread.condvarany.intwait "32.7.5.3 Interruptible waits"), interruptible waitstemplate<class Lock, class Predicate>bool wait(Lock& lock, stop_token stoken, Predicate pred); template<class Lock, class Clock, class Duration, class Predicate>bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period, class Predicate>bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred); };}
|
||||
|
||||
[ð](#lib:condition_variable_any,constructor)
|
||||
|
||||
`condition_variable_any();
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10067)
|
||||
|
||||
*Throws*: bad_alloc or system_error when an exception is
|
||||
required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10072)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
resource_unavailable_try_again â if some non-memory resource
|
||||
limitation prevents initialization[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
operation_not_permitted â if the thread does not have the
|
||||
privilege to perform the operation[.](#3.2.sentence-1)
|
||||
|
||||
[ð](#lib:condition_variable_any,destructor)
|
||||
|
||||
`~condition_variable_any();
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10089)
|
||||
|
||||
*Preconditions*: There is no thread blocked on *this[.](#4.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
That is, all
|
||||
threads have been notified; they can subsequently block on the lock specified in the
|
||||
wait[.](#4.sentence-2)
|
||||
|
||||
This relaxes the usual rules, which would have required all wait calls to happen before
|
||||
destruction[.](#4.sentence-3)
|
||||
|
||||
Only the notification to unblock the wait needs to happen before destruction[.](#4.sentence-4)
|
||||
|
||||
Undefined behavior ensues if a thread waits on *this once the destructor has
|
||||
been started, especially when the waiting threads are calling the wait functions in a loop or
|
||||
using the overloads of wait, wait_for, or wait_until that take a predicate[.](#4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:notify_one,condition_variable_any)
|
||||
|
||||
`void notify_one() noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10110)
|
||||
|
||||
*Effects*: If any threads are blocked waiting for *this, unblocks one of those threads[.](#5.sentence-1)
|
||||
|
||||
[ð](#lib:notify_all,condition_variable_any)
|
||||
|
||||
`void notify_all() noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10121)
|
||||
|
||||
*Effects*: Unblocks all threads that are blocked waiting for *this[.](#6.sentence-1)
|
||||
56
cppdraft/thread/condition/general.md
Normal file
56
cppdraft/thread/condition/general.md
Normal file
@@ -0,0 +1,56 @@
|
||||
[thread.condition.general]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#general)
|
||||
|
||||
### 32.7.1 General [thread.condition.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9482)
|
||||
|
||||
Condition variables provide synchronization primitives used to block a thread until
|
||||
notified by some other thread that some condition is met or until a system time is
|
||||
reached[.](#1.sentence-1)
|
||||
|
||||
Class condition_variable provides a condition variable that can only
|
||||
wait on an object of type unique_lock<mutex>, allowing the implementation
|
||||
to be more efficient[.](#1.sentence-2)
|
||||
|
||||
Class condition_variable_any provides a general
|
||||
condition variable that can wait on objects of user-supplied lock types[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9490)
|
||||
|
||||
Condition variables permit concurrent invocation of the wait, wait_for,wait_until, notify_one and notify_all member functions[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9494)
|
||||
|
||||
The executions of notify_one and notify_all are atomic[.](#3.sentence-1)
|
||||
|
||||
The executions of wait, wait_for, and wait_until are performed
|
||||
in three atomic parts:
|
||||
|
||||
| [1.](#3.1) | the release of the mutex and entry into the waiting state; |
|
||||
| --- | --- |
|
||||
| [2.](#3.2) | the unblocking of the wait; and |
|
||||
| [3.](#3.3) | the reacquisition of the lock[.](#3.sentence-2) |
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9505)
|
||||
|
||||
The implementation behaves as if all executions of notify_one, notify_all, and each
|
||||
part of the wait, wait_for, and wait_until executions are
|
||||
executed in a single unspecified total order consistent with the âhappens beforeâ order[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9510)
|
||||
|
||||
Condition variable construction and destruction need not be synchronized[.](#5.sentence-1)
|
||||
74
cppdraft/thread/condition/nonmember.md
Normal file
74
cppdraft/thread/condition/nonmember.md
Normal file
@@ -0,0 +1,74 @@
|
||||
[thread.condition.nonmember]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.7 Condition variables [[thread.condition]](thread.condition#nonmember)
|
||||
|
||||
### 32.7.3 Non-member functions [thread.condition.nonmember]
|
||||
|
||||
[ð](#lib:notify_all_at_thread_exit)
|
||||
|
||||
`void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9537)
|
||||
|
||||
*Preconditions*: lk is locked by the calling thread and either
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
no other thread is waiting on cond, or
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
lk.mutex() returns the same value for each of the lock arguments
|
||||
supplied by all concurrently waiting (via wait, wait_for,
|
||||
or wait_until) threads[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9547)
|
||||
|
||||
*Effects*: Transfers ownership of the lock associated with lk into
|
||||
internal storage and schedules cond to be notified when the current
|
||||
thread exits, after all objects with thread storage duration associated with
|
||||
the current thread have been destroyed[.](#2.sentence-1)
|
||||
|
||||
This notification is equivalent to:lk.unlock();
|
||||
cond.notify_all();
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9558)
|
||||
|
||||
*Synchronization*: The implied lk.unlock() call is sequenced after the destruction of
|
||||
all objects with thread storage duration associated with the current thread[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9563)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The supplied lock is held until the thread exits,
|
||||
which might cause deadlock due to lock ordering issues[.](#4.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9569)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
It is the user's responsibility to ensure that waiting threads
|
||||
do not incorrectly assume that the thread has finished if they experience
|
||||
spurious wakeups[.](#5.sentence-1)
|
||||
|
||||
This typically requires that the condition being waited
|
||||
for is satisfied while holding the lock on lk, and that this lock
|
||||
is not released and reacquired prior to calling notify_all_at_thread_exit[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
138
cppdraft/thread/condvarany/intwait.md
Normal file
138
cppdraft/thread/condvarany/intwait.md
Normal 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.2 The 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.4 Timing 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.2 The 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));
|
||||
223
cppdraft/thread/condvarany/wait.md
Normal file
223
cppdraft/thread/condvarany/wait.md
Normal 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.2 The 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.4 Timing 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.4 Timing 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.4 Timing 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.2 The 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.4 Timing 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.4 Timing 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.2 The 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
517
cppdraft/thread/coord.md
Normal 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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.3 Class 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.3 Class 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.3 Class 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Template 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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*]
|
||||
16
cppdraft/thread/coord/general.md
Normal file
16
cppdraft/thread/coord/general.md
Normal 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.9 Coordination 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)
|
||||
28
cppdraft/thread/general.md
Normal file
28
cppdraft/thread/general.md
Normal 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.2 Multi-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.2 Requirements") | Requirements | |
|
||||
| [ð](#tab:thread.summary-row-3)<br>[[thread.stoptoken]](thread.stoptoken "32.3 Stop tokens") | Stop tokens | <stop_token> |
|
||||
| [ð](#tab:thread.summary-row-4)<br>[[thread.threads]](thread.threads "32.4 Threads") | Threads | <thread> |
|
||||
| [ð](#tab:thread.summary-row-5)<br>[[atomics]](atomics "32.5 Atomic operations") | Atomic operations | <atomic>, <stdatomic.h> |
|
||||
| [ð](#tab:thread.summary-row-6)<br>[[thread.mutex]](thread.mutex "32.6 Mutual exclusion") | Mutual exclusion | <mutex>, <shared_mutex> |
|
||||
| [ð](#tab:thread.summary-row-7)<br>[[thread.condition]](thread.condition "32.7 Condition variables") | Condition variables | <condition_variable> |
|
||||
| [ð](#tab:thread.summary-row-8)<br>[[thread.sema]](thread.sema "32.8 Semaphore") | Semaphores | <semaphore> |
|
||||
| [ð](#tab:thread.summary-row-9)<br>[[thread.coord]](thread.coord "32.9 Coordination types") | Coordination types | <latch>, <barrier> |
|
||||
| [ð](#tab:thread.summary-row-10)<br>[[futures]](futures "32.10 Futures") | Futures | <future> |
|
||||
| [ð](#tab:thread.summary-row-11)<br>[[saferecl]](saferecl "32.11 Safe reclamation") | Safe reclamation | <rcu>, <hazard_pointer> |
|
||||
400
cppdraft/thread/jthread/class.md
Normal file
400
cppdraft/thread/jthread/class.md
Normal 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.3 Class thread"))
|
||||
with the additional abilities to provide
|
||||
a stop_token ([[thread.stoptoken]](thread.stoptoken "32.3 Stop 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.2 Constructors, 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.3 Members"), 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.3 Native handles")// [[thread.jthread.stop]](#thread.jthread.stop "32.4.4.4 Stop 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.5 Specialized algorithms"), specialized algorithmsfriend void swap(jthread& lhs, jthread& rhs) noexcept; // [[thread.jthread.static]](#thread.jthread.static "32.4.4.6 Static 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.5 invoke 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.5 Temporary 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.2 Multi-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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
33
cppdraft/thread/jthread/class/general.md
Normal file
33
cppdraft/thread/jthread/class/general.md
Normal 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.3 Class thread"))
|
||||
with the additional abilities to provide
|
||||
a stop_token ([[thread.stoptoken]](thread.stoptoken "32.3 Stop 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.2 Constructors, 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.3 Members"), 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.3 Native handles")// [[thread.jthread.stop]](thread.jthread.stop "32.4.4.4 Stop 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.5 Specialized algorithms"), specialized algorithmsfriend void swap(jthread& lhs, jthread& rhs) noexcept; // [[thread.jthread.static]](thread.jthread.static "32.4.4.6 Static members"), static membersstatic unsigned int hardware_concurrency() noexcept; private: stop_source ssource; // *exposition only*};}
|
||||
177
cppdraft/thread/jthread/cons.md
Normal file
177
cppdraft/thread/jthread/cons.md
Normal 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.5 invoke 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.5 Temporary 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)
|
||||
143
cppdraft/thread/jthread/mem.md
Normal file
143
cppdraft/thread/jthread/mem.md
Normal 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.2 Multi-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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
20
cppdraft/thread/jthread/special.md
Normal file
20
cppdraft/thread/jthread/special.md
Normal 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)
|
||||
20
cppdraft/thread/jthread/static.md
Normal file
20
cppdraft/thread/jthread/static.md
Normal 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)
|
||||
42
cppdraft/thread/jthread/stop.md
Normal file
42
cppdraft/thread/jthread/stop.md
Normal 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
177
cppdraft/thread/latch.md
Normal 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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();
|
||||
155
cppdraft/thread/latch/class.md
Normal file
155
cppdraft/thread/latch/class.md
Normal 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.2 Exceptions"))[.](#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.2 Mutex 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.2 Exceptions"))[.](#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.2 Mutex 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();
|
||||
23
cppdraft/thread/latch/general.md
Normal file
23
cppdraft/thread/latch/general.md
Normal 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
1258
cppdraft/thread/lock.md
Normal file
File diff suppressed because it is too large
Load Diff
79
cppdraft/thread/lock/algorithm.md
Normal file
79
cppdraft/thread/lock/algorithm.md
Normal 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.3 Cpp17Lockable 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.3 Cpp17Lockable 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)
|
||||
44
cppdraft/thread/lock/general.md
Normal file
44
cppdraft/thread/lock/general.md
Normal 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 { };}
|
||||
78
cppdraft/thread/lock/guard.md
Normal file
78
cppdraft/thread/lock/guard.md
Normal 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.4 Lifetime [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.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable 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()
|
||||
91
cppdraft/thread/lock/scoped.md
Normal file
91
cppdraft/thread/lock/scoped.md
Normal 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.4 Lifetime [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.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#1.1.sentence-2)
|
||||
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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)
|
||||
525
cppdraft/thread/lock/shared.md
Normal file
525
cppdraft/thread/lock/shared.md
Normal 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.2 Constructors, 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.3 Locking"), 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.4 Modifiers"), modifiersvoid swap(shared_lock& u) noexcept;
|
||||
mutex_type* release() noexcept; // [[thread.lock.shared.obs]](#obs "32.6.5.5.5 Observers"), 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.4 Lifetime")) of the shared_lock object[.](#general-1.sentence-4)
|
||||
|
||||
The suppliedMutex type shall meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5 Cpp17SharedLockable 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable requirements"))[.](#general-2.sentence-1)
|
||||
|
||||
If Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable requirements")),shared_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.2 Exceptions"))[.](#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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
175
cppdraft/thread/lock/shared/cons.md
Normal file
175
cppdraft/thread/lock/shared/cons.md
Normal 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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)
|
||||
57
cppdraft/thread/lock/shared/general.md
Normal file
57
cppdraft/thread/lock/shared/general.md
Normal 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.2 Constructors, 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.3 Locking"), 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.4 Modifiers"), modifiersvoid swap(shared_lock& u) noexcept;
|
||||
mutex_type* release() noexcept; // [[thread.lock.shared.obs]](thread.lock.shared.obs "32.6.5.5.5 Observers"), 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.4 Lifetime")) of the shared_lock object[.](#1.sentence-4)
|
||||
|
||||
The suppliedMutex type shall meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5 Cpp17SharedLockable 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable requirements"))[.](#2.sentence-1)
|
||||
|
||||
If Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable requirements")),shared_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable requirements"))[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
234
cppdraft/thread/lock/shared/locking.md
Normal file
234
cppdraft/thread/lock/shared/locking.md
Normal 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.2 Exceptions"))[.](#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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
51
cppdraft/thread/lock/shared/mod.md
Normal file
51
cppdraft/thread/lock/shared/mod.md
Normal 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)
|
||||
44
cppdraft/thread/lock/shared/obs.md
Normal file
44
cppdraft/thread/lock/shared/obs.md
Normal 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)
|
||||
548
cppdraft/thread/lock/unique.md
Normal file
548
cppdraft/thread/lock/unique.md
Normal 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.2 Constructors, 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.3 Locking"), 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.4 Modifiers"), modifiersvoid swap(unique_lock& u) noexcept;
|
||||
mutex_type* release() noexcept; // [[thread.lock.unique.obs]](#obs "32.6.5.4.5 Observers"), 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.4 Lifetime")) of the unique_lock object[.](#general-1.sentence-4)
|
||||
|
||||
The suppliedMutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#general-1.sentence-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.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements[.](#general-2.sentence-1)
|
||||
|
||||
If Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable requirements")),unique_lock<Mutex> also meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements;
|
||||
if Mutex meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable requirements")),unique_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.2 Exceptions"))[.](#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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.2 Exceptions"))[.](#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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.2 Exceptions"))[.](#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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
187
cppdraft/thread/lock/unique/cons.md
Normal file
187
cppdraft/thread/lock/unique/cons.md
Normal 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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)
|
||||
59
cppdraft/thread/lock/unique/general.md
Normal file
59
cppdraft/thread/lock/unique/general.md
Normal 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.2 Constructors, 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.3 Locking"), 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.4 Modifiers"), modifiersvoid swap(unique_lock& u) noexcept;
|
||||
mutex_type* release() noexcept; // [[thread.lock.unique.obs]](thread.lock.unique.obs "32.6.5.4.5 Observers"), 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.4 Lifetime")) of the unique_lock object[.](#1.sentence-4)
|
||||
|
||||
The suppliedMutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2 Cpp17BasicLockable requirements"))[.](#1.sentence-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.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements[.](#2.sentence-1)
|
||||
|
||||
If Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable requirements")),unique_lock<Mutex> also meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements;
|
||||
if Mutex meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable requirements")),unique_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
243
cppdraft/thread/lock/unique/locking.md
Normal file
243
cppdraft/thread/lock/unique/locking.md
Normal 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.2 Exceptions"))[.](#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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.2 Exceptions"))[.](#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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.2 Exceptions"))[.](#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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
51
cppdraft/thread/lock/unique/mod.md
Normal file
51
cppdraft/thread/lock/unique/mod.md
Normal 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)
|
||||
44
cppdraft/thread/lock/unique/obs.md
Normal file
44
cppdraft/thread/lock/unique/obs.md
Normal 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
2546
cppdraft/thread/mutex.md
Normal file
File diff suppressed because it is too large
Load Diff
77
cppdraft/thread/mutex/class.md
Normal file
77
cppdraft/thread/mutex/class.md
Normal 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#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.4 Mutex requirements"))[.](#3.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
17
cppdraft/thread/mutex/general.md
Normal file
17
cppdraft/thread/mutex/general.md
Normal 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.6 Mutual 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.2 Multi-threaded executions and data races"))[.](#1.sentence-2)
|
||||
71
cppdraft/thread/mutex/recursive.md
Normal file
71
cppdraft/thread/mutex/recursive.md
Normal 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#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.4 Mutex requirements"))[.](#2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
1091
cppdraft/thread/mutex/requirements.md
Normal file
1091
cppdraft/thread/mutex/requirements.md
Normal file
File diff suppressed because it is too large
Load Diff
25
cppdraft/thread/mutex/requirements/general.md
Normal file
25
cppdraft/thread/mutex/requirements/general.md
Normal 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.5 Requirements 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)
|
||||
382
cppdraft/thread/mutex/requirements/mutex.md
Normal file
382
cppdraft/thread/mutex/requirements/mutex.md
Normal 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.1 General [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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.2 Template argument requirements [utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template 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.2 Multi-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.2 Multi-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.2 Multi-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.2 Exceptions"))[.](#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.5 Atomic 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.2 Multi-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.2 Multi-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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.4 Mutex requirements"))[.](#thread.mutex.class-3.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.4 Mutex requirements"))[.](#thread.mutex.recursive-2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
252
cppdraft/thread/mutex/requirements/mutex/general.md
Normal file
252
cppdraft/thread/mutex/requirements/mutex/general.md
Normal 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.1 General [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.2 Mutex 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.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable 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.2 Template argument requirements [utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template 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.2 Multi-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.2 Multi-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.2 Multi-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.2 Exceptions"))[.](#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.5 Atomic 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.2 Multi-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.2 Multi-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
109
cppdraft/thread/once.md
Normal 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.4 Requirements"))[.](#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.2 Multi-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.2 Exceptions")), 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*]
|
||||
75
cppdraft/thread/once/callonce.md
Normal file
75
cppdraft/thread/once/callonce.md
Normal 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.4 Requirements"))[.](#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.2 Multi-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.2 Exceptions")), 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*]
|
||||
41
cppdraft/thread/once/onceflag.md
Normal file
41
cppdraft/thread/once/onceflag.md
Normal 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
576
cppdraft/thread/req.md
Normal 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.10 Function 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.2 Boolean testability [concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2 Boolean 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.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock 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.8 Class 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.14 Restrictions 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.5 System 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 "30 Time 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.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock 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.7 Clocks") 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.1 General [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.4 Class template unique_lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5 Class template shared_lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3 Class template scoped_lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2 Class template lock_guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6 Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_variable_any")) all operate on user-supplied
|
||||
lockable objects[.](#lockable.general-3.sentence-1)
|
||||
|
||||
The [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements,
|
||||
the [*Cpp17TimedLockable*](#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements,
|
||||
the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements, and
|
||||
the [*Cpp17SharedTimedLockable*](#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable 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.1 General [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.1 General [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.2 Cpp17BasicLockable 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.3 Cpp17Lockable 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.5 Class template duration [time.duration]"), and abs_time denotes a value
|
||||
of an instantiation of [time_point](time.point "30.6 Class 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.4 Timing 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.4 Timing 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.5 Cpp17SharedLockable 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.4 Timing 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.4 Timing 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)
|
||||
45
cppdraft/thread/req/exception.md
Normal file
45
cppdraft/thread/req/exception.md
Normal 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.8 Class 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.14 Restrictions 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.5 System 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)
|
||||
358
cppdraft/thread/req/lockable.md
Normal file
358
cppdraft/thread/req/lockable.md
Normal 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.1 General [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.4 Class template unique_lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5 Class template shared_lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3 Class template scoped_lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2 Class template lock_guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6 Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_variable_any")) all operate on user-supplied
|
||||
lockable objects[.](#general-3.sentence-1)
|
||||
|
||||
The [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements,
|
||||
the [*Cpp17TimedLockable*](#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements,
|
||||
the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements, and
|
||||
the [*Cpp17SharedTimedLockable*](#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable 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.1 General [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.1 General [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.2 Cpp17BasicLockable 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.3 Cpp17Lockable 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.5 Class template duration [time.duration]"), and abs_time denotes a value
|
||||
of an instantiation of [time_point](time.point "30.6 Class 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.4 Timing 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.4 Timing 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.5 Cpp17SharedLockable 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.4 Timing 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.4 Timing 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)
|
||||
53
cppdraft/thread/req/lockable/basic.md
Normal file
53
cppdraft/thread/req/lockable/basic.md
Normal 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)
|
||||
80
cppdraft/thread/req/lockable/general.md
Normal file
80
cppdraft/thread/req/lockable/general.md
Normal 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.1 General [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.4 Class template unique_lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5 Class template shared_lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3 Class template scoped_lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2 Class template lock_guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6 Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_variable_any")) all operate on user-supplied
|
||||
lockable objects[.](#3.sentence-1)
|
||||
|
||||
The [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements,
|
||||
the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements,
|
||||
the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements, and
|
||||
the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable 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.1 General [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.1 General [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*]
|
||||
42
cppdraft/thread/req/lockable/req.md
Normal file
42
cppdraft/thread/req/lockable/req.md
Normal 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.2 Cpp17BasicLockable 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)
|
||||
74
cppdraft/thread/req/lockable/shared.md
Normal file
74
cppdraft/thread/req/lockable/shared.md
Normal 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)
|
||||
65
cppdraft/thread/req/lockable/shared/timed.md
Normal file
65
cppdraft/thread/req/lockable/shared/timed.md
Normal 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.5 Cpp17SharedLockable 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.4 Timing 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.4 Timing 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)
|
||||
79
cppdraft/thread/req/lockable/timed.md
Normal file
79
cppdraft/thread/req/lockable/timed.md
Normal 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.3 Cpp17Lockable 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.5 Class template duration [time.duration]"), and abs_time denotes a value
|
||||
of an instantiation of [time_point](time.point "30.6 Class 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.4 Timing 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.4 Timing 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)
|
||||
27
cppdraft/thread/req/native.md
Normal file
27
cppdraft/thread/req/native.md
Normal 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*]
|
||||
28
cppdraft/thread/req/paramname.md
Normal file
28
cppdraft/thread/req/paramname.md
Normal 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.10 Function 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.2 Boolean testability [concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2 Boolean 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.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock requirements"));
|
||||
the program is ill-formed if is_clock_v<C> is false[.](#1.sentence-6)
|
||||
138
cppdraft/thread/req/timing.md
Normal file
138
cppdraft/thread/req/timing.md
Normal 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 "30 Time 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.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock 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.7 Clocks") 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
251
cppdraft/thread/sema.md
Normal 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.3 Class 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.2 Header <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.2 Exceptions"))[.](#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.2 Mutex 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.5 Atomic 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.2 Exceptions"))[.](#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.2 Mutex 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.4 Timing 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.4 Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#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.2 Mutex types"))[.](#cnt-20.sentence-1)
|
||||
221
cppdraft/thread/sema/cnt.md
Normal file
221
cppdraft/thread/sema/cnt.md
Normal 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.2 Exceptions"))[.](#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.2 Mutex 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.5 Atomic 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.2 Exceptions"))[.](#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.2 Mutex 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.4 Timing 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.4 Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#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.2 Mutex types"))[.](#20.sentence-1)
|
||||
29
cppdraft/thread/sema/general.md
Normal file
29
cppdraft/thread/sema/general.md
Normal 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)
|
||||
58
cppdraft/thread/sharedmutex/class.md
Normal file
58
cppdraft/thread/sharedmutex/class.md
Normal 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#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.4 Shared mutex types"))[.](#2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
247
cppdraft/thread/sharedmutex/requirements.md
Normal file
247
cppdraft/thread/sharedmutex/requirements.md
Normal 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.1 General [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.2 Mutex 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.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5 Cpp17SharedLockable 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.2 Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1 General [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.2 Multi-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.2 Exceptions"))[.](#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.2 Multi-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.2 Multi-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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.2 Properties 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)
|
||||
198
cppdraft/thread/sharedmutex/requirements/general.md
Normal file
198
cppdraft/thread/sharedmutex/requirements/general.md
Normal 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.1 General [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.2 Mutex 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.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5 Cpp17SharedLockable 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.2 Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1 General [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.2 Multi-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.2 Exceptions"))[.](#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.2 Multi-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.2 Multi-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)
|
||||
52
cppdraft/thread/sharedtimedmutex/class.md
Normal file
52
cppdraft/thread/sharedtimedmutex/class.md
Normal 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.5 Shared timed mutex types"))[.](#2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
201
cppdraft/thread/sharedtimedmutex/requirements.md
Normal file
201
cppdraft/thread/sharedtimedmutex/requirements.md
Normal 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.1 General [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.3 Timed mutex types")),
|
||||
shared mutex types ([[thread.sharedmutex.requirements]](thread.sharedmutex.requirements "32.6.4.4 Shared 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.5 Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6 Class 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing 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.2 Properties 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)
|
||||
158
cppdraft/thread/sharedtimedmutex/requirements/general.md
Normal file
158
cppdraft/thread/sharedtimedmutex/requirements/general.md
Normal 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.1 General [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.3 Timed mutex types")),
|
||||
shared mutex types ([[thread.sharedmutex.requirements]](thread.sharedmutex.requirements "32.6.4.4 Shared 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.5 Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6 Class 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing specifications"))[.](#15.sentence-1)
|
||||
871
cppdraft/thread/stoptoken.md
Normal file
871
cppdraft/thread/stoptoken.md
Normal 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.1 Introduction [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.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), and[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") specify the required syntax and semantics of
|
||||
shared access to a [*stop state*](#def:stop_state "32.3.1 Introduction [thread.stoptoken.intro]")[.](#intro-2.sentence-1)
|
||||
|
||||
Any object modeling [*stoppable-source*](#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), or[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") that refers to the same stop state is
|
||||
an [*associated*](#def:associated "32.3.1 Introduction [thread.stoptoken.intro]")[*stoppable-source*](#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), or[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") will be visible to
|
||||
all associated [stoppable_token](#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") and[*stoppable-source*](#concept:stoppable-source "32.3.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") are called when a stop request is first made
|
||||
by any associated [*stoppable-source*](#concept:stoppable-source "32.3.3 Stop 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.3 Stop token concepts"), stop token conceptstemplate<class CallbackFn, class Token, class Initializer = CallbackFn>concept [*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; // *exposition only*template<class Token>concept [stoppable_token](#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; template<class Token>concept [unstoppable_token](#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; template<class Source>concept [*stoppable-source*](#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; // *exposition only*// [[stoptoken]](#stoptoken "32.3.4 Class stop_token"), class stop_tokenclass stop_token; // [[stopsource]](#stopsource "32.3.5 Class 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.6 Class template stop_callback"), class template stop_callbacktemplate<class Callback>class stop_callback; // [[stoptoken.never]](#stoptoken.never "32.3.7 Class never_stop_token"), class never_stop_tokenclass never_stop_token; // [[stoptoken.inplace]](#stoptoken.inplace "32.3.8 Class inplace_stop_token"), class inplace_stop_tokenclass inplace_stop_token; // [[stopsource.inplace]](#stopsource.inplace "32.3.9 Class inplace_stop_source"), class inplace_stop_sourceclass inplace_stop_source; // [[stopcallback.inplace]](#stopcallback.inplace "32.3.10 Class 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") = // *exposition only*[invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<CallbackFn> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<CallbackFn, Initializer> &&requires { typename stop_callback_for_t<Token, CallbackFn>; } &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept 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.2 Concept 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.3 Stop 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.11 Concept constructible_from [concept.constructible]")<SCB, Token, Initializer>
|
||||
|
||||
* [(3.1.2)](#stoptoken.concepts-3.1.2)
|
||||
|
||||
[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<SCB, Token&, Initializer>
|
||||
|
||||
* [(3.1.3)](#stoptoken.concepts-3.1.3)
|
||||
|
||||
[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept 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.3 Stop 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.3 Stop 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.6 block"))
|
||||
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.2 Data 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") concept checks
|
||||
for a [stoppable_token](#concept:stoppable_token "32.3.3 Stop 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.3 Stop 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.2 Concept same_as [concept.same]")<bool>; { tok.stop_possible() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<bool>; { Token(tok) } noexcept; // see implicit expression variations ([[concepts.equality]](concepts.equality "18.2 Equality preservation"))} &&[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<Token> &&[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<Token>;
|
||||
|
||||
template<class Token>concept [unstoppable_token](#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") =[stoppable_token](#concept:stoppable_token "32.3.3 Stop 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") object with no associated stop state
|
||||
is said to be [*disengaged*](#def:disengaged "32.3.3 Stop 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.3 Stop 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.2 Data 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.3 Stop token concepts [stoptoken.concepts]")<CallbackFn, Token, Initializer> is satisfied,[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") = // *exposition only*requires (Source& src, const Source csrc) { // see implicit expression variations ([[concepts.equality]](concepts.equality "18.2 Equality preservation")){ csrc.get_token() } -> stoppable_token; { csrc.stop_possible() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<bool>; { csrc.stop_requested() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<bool>; { src.request_stop() } -> [same_as](concept.same#concept:same_as "18.4.2 Concept 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.3 Stop 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.3 Stop 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.3 Stop 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") or [*stoppable-source*](#concept:stoppable-source "32.3.3 Stop 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.3 Stop 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.3 Stop 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.2 Data 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.2 The 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.3 Interruptible 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.3 Stop 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.5 Class 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.2 Member 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.2 Constructors, copy, and assignment"), constructors, copy, and assignment stop_source(); explicit stop_source(nostopstate_t) noexcept {}// [[stopsource.mem]](#stopsource.mem "32.3.5.3 Member 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.3 Stop token concepts [stoptoken.concepts]"),[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]"),[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]"), and[swappable](concept.swappable#concept:swappable "18.4.9 Concept 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.3 Stop 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.2 Constructors 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.2 Concept invocable [concept.invocable]") and [destructible](concept.destructible#concept:destructible "18.4.10 Concept 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.3 Stop token concepts [stoptoken.concepts]")<CallbackFn, stop_token, Initializer> is satisfied, then[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop 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.3 Stop 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.11 Concept 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.3 Stop 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.3 Stop 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.3 Stop 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.3 Stop 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.9 Class 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.2 Member 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.4 Lifetime"),
|
||||
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.1 General"),
|
||||
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.3 Stop 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.2 Constructors"), 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.3 Member 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.3 Stop 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.2 Constructors 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.2 Concept invocable [concept.invocable]") and [destructible](concept.destructible#concept:destructible "18.4.10 Concept 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.3 Stop token concepts [stoptoken.concepts]")<CallbackFn, inplace_stop_token, Initializer> is satisfied, then[*stoppable-callback-for*](#concept:stoppable-callback-for "32.3.3 Stop 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.3 Stop 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.11 Concept 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.3 Stop 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.3 Stop token concepts"))[.](#stopcallback.inplace.cons-3.sentence-1)
|
||||
85
cppdraft/thread/stoptoken/intro.md
Normal file
85
cppdraft/thread/stoptoken/intro.md
Normal 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.3 Stop 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.1 Introduction [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.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), and[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") specify the required syntax and semantics of
|
||||
shared access to a [*stop state*](#def:stop_state "32.3.1 Introduction [thread.stoptoken.intro]")[.](#2.sentence-1)
|
||||
|
||||
Any object modeling [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), or[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") that refers to the same stop state is
|
||||
an [*associated*](#def:associated "32.3.1 Introduction [thread.stoptoken.intro]")[*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]"),[stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"), or[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop 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.3 Stop 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.3 Stop token concepts [stoptoken.concepts]") will be visible to
|
||||
all associated [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") and[*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop 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.3 Stop 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.3 Stop 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*]
|
||||
11
cppdraft/thread/stoptoken/syn.md
Normal file
11
cppdraft/thread/stoptoken/syn.md
Normal 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.3 Stop token concepts"), stop token conceptstemplate<class CallbackFn, class Token, class Initializer = CallbackFn>concept [*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; // *exposition only*template<class Token>concept [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; template<class Token>concept [unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; template<class Source>concept [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]") = *see below*; // *exposition only*// [[stoptoken]](stoptoken "32.3.4 Class stop_token"), class stop_tokenclass stop_token; // [[stopsource]](stopsource "32.3.5 Class 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.6 Class template stop_callback"), class template stop_callbacktemplate<class Callback>class stop_callback; // [[stoptoken.never]](stoptoken.never "32.3.7 Class never_stop_token"), class never_stop_tokenclass never_stop_token; // [[stoptoken.inplace]](stoptoken.inplace "32.3.8 Class inplace_stop_token"), class inplace_stop_tokenclass inplace_stop_token; // [[stopsource.inplace]](stopsource.inplace "32.3.9 Class inplace_stop_source"), class inplace_stop_sourceclass inplace_stop_source; // [[stopcallback.inplace]](stopcallback.inplace "32.3.10 Class 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
11
cppdraft/thread/syn.md
Normal 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.1 Header <compare> synopsis")namespace std {// [[thread.thread.class]](thread.thread.class "32.4.3 Class thread"), class threadclass thread; void swap(thread& x, thread& y) noexcept; // [[thread.jthread.class]](thread.jthread.class "32.4.4 Class jthread"), class jthreadclass jthread; // [[thread.thread.this]](thread.thread.this "32.4.5 Namespace 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); }}
|
||||
20
cppdraft/thread/thread/algorithm.md
Normal file
20
cppdraft/thread/thread/algorithm.md
Normal 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)
|
||||
35
cppdraft/thread/thread/assign.md
Normal file
35
cppdraft/thread/thread/assign.md
Normal 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.2 The 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)
|
||||
547
cppdraft/thread/thread/class.md
Normal file
547
cppdraft/thread/thread/class.md
Normal 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.2 Class thread::id"), class thread::idclass id; using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.6 Members"), 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.3 Native 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.2 Class 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.2 Properties 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.8 Sorting 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.2 Standard 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.19 Class 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.5 invoke functions")auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5 Temporary 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.2 The 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.2 The 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.2 The 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.2 Multi-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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
46
cppdraft/thread/thread/class/general.md
Normal file
46
cppdraft/thread/thread/class/general.md
Normal 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.2 Class thread::id"), class thread::idclass id; using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.6 Members"), 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.3 Native handles")// static membersstatic unsigned int hardware_concurrency() noexcept; };}
|
||||
117
cppdraft/thread/thread/constr.md
Normal file
117
cppdraft/thread/thread/constr.md
Normal 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.5 invoke functions")auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5 Temporary 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.2 The 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)
|
||||
33
cppdraft/thread/thread/destr.md
Normal file
33
cppdraft/thread/thread/destr.md
Normal 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.2 The 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*]
|
||||
170
cppdraft/thread/thread/id.md
Normal file
170
cppdraft/thread/thread/id.md
Normal 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.3 Class 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.2 Class 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.2 Properties 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.8 Sorting 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.2 Standard 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.19 Class template hash"))[.](#14.sentence-1)
|
||||
145
cppdraft/thread/thread/member.md
Normal file
145
cppdraft/thread/thread/member.md
Normal 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.2 Multi-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.2 Exceptions"))[.](#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.2 Exceptions"))[.](#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)
|
||||
30
cppdraft/thread/thread/static.md
Normal file
30
cppdraft/thread/thread/static.md
Normal 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)
|
||||
92
cppdraft/thread/thread/this.md
Normal file
92
cppdraft/thread/thread/this.md
Normal 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.4 Timing 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.4 Timing 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.4 Timing 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.4 Timing specifications"))[.](#9.sentence-1)
|
||||
1049
cppdraft/thread/threads.md
Normal file
1049
cppdraft/thread/threads.md
Normal file
File diff suppressed because it is too large
Load Diff
19
cppdraft/thread/threads/general.md
Normal file
19
cppdraft/thread/threads/general.md
Normal 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.4 Threads") 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*]
|
||||
59
cppdraft/thread/timedmutex/class.md
Normal file
59
cppdraft/thread/timedmutex/class.md
Normal 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#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.3 Timed mutex types"))[.](#2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
73
cppdraft/thread/timedmutex/recursive.md
Normal file
73
cppdraft/thread/timedmutex/recursive.md
Normal 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#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.3 Timed mutex types"))[.](#2.sentence-1)
|
||||
|
||||
It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)
|
||||
264
cppdraft/thread/timedmutex/requirements.md
Normal file
264
cppdraft/thread/timedmutex/requirements.md
Normal 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.1 General [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.5 Class template duration [time.duration]"), and abs_time denotes an
|
||||
object of an
|
||||
instantiation of [time_point](time.point "30.6 Class 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.2 Properties 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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.2 Properties 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)
|
||||
150
cppdraft/thread/timedmutex/requirements/general.md
Normal file
150
cppdraft/thread/timedmutex/requirements/general.md
Normal 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.1 General [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.5 Class template duration [time.duration]"), and abs_time denotes an
|
||||
object of an
|
||||
instantiation of [time_point](time.point "30.6 Class 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing specifications"))[.](#15.sentence-1)
|
||||
Reference in New Issue
Block a user