Files
cppdraft_translate/cppdraft/exec/scope.md
2025-10-25 03:02:53 +03:00

461 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[exec.scope]
# 33 Execution control library [[exec]](./#exec)
## 33.14 Execution scope utilities [exec.scope]
### [33.14.1](#concepts) Execution scope concepts [[exec.scope.concepts]](exec.scope.concepts)
[1](#concepts-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7711)
The [scope_token](#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") concept defines the requirements on
a type Token that can be used to create associations
between senders and an async scope[.](#concepts-1.sentence-1)
[2](#concepts-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7716)
Let *test-sender* and *test-env* be unspecified types such that[sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<*test-sender*, *test-env*> is modeled[.](#concepts-2.sentence-1)
namespace std::execution {template<class Token>concept [scope_token](#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") =[copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<Token> &&requires(const Token token) {{ token.try_associate() } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<bool>; { token.disassociate() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<void>; { token.wrap(declval<*test-sender*>()) } -> [sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<*test-env*>; };}
[3](#concepts-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7735)
A type Token models [scope_token](#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") only if:
- [(3.1)](#concepts-3.1)
no exceptions are thrown from
copy construction,
move construction,
copy assignment, or
move assignment
of objects of type Token; and
- [(3.2)](#concepts-3.2)
given an lvalue token of type (possibly const) Token,
for all expressions sndr such thatdecltype((
sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]"):
* [(3.2.1)](#concepts-3.2.1)
token.wrap(sndr) is a valid expression,
* [(3.2.2)](#concepts-3.2.2)
decltype(token.wrap(sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]"), and
* [(3.2.3)](#concepts-3.2.3)
completion_signatures_of_t<decltype(token.wrap(sndr)), E> contains the same completion signatures as completion_signatures_of_t<decltype((sndr)), E> for all types E such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<decltype((sndr)), E> is modeled.
### [33.14.2](#exec.counting.scopes) Counting Scopes [[exec.counting.scopes]](exec.counting.scopes)
#### [33.14.2.1](#exec.counting.scopes.general) General [[exec.counting.scopes.general]](exec.counting.scopes.general)
[1](#exec.counting.scopes.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7769)
Scopes of type simple_counting_scope and counting_scope maintain counts of associations[.](#exec.counting.scopes.general-1.sentence-1)
Let:
- [(1.1)](#exec.counting.scopes.general-1.1)
Scope be either simple_counting_scope or counting_scope,
- [(1.2)](#exec.counting.scopes.general-1.2)
scope be an object of type Scope,
- [(1.3)](#exec.counting.scopes.general-1.3)
tkn be an object of type Scope::token obtained from scope.get_token(),
- [(1.4)](#exec.counting.scopes.general-1.4)
jsndr be a sender obtained from scope.join(), and
- [(1.5)](#exec.counting.scopes.general-1.5)
op be an operation state obtained from
connecting jsndr to a receiver[.](#exec.counting.scopes.general-1.sentence-2)
During its lifetime scope goes through different states
which govern what operations are allowed and the result of these operations:
- [(1.6)](#exec.counting.scopes.general-1.6)
*unused*:
a newly constructed object starts in the *unused* state[.](#exec.counting.scopes.general-1.6.sentence-1)
- [(1.7)](#exec.counting.scopes.general-1.7)
*open*:
when tkn.try_associate() is called
while scope is in the *unused* state,scope moves to the *open* state[.](#exec.counting.scopes.general-1.7.sentence-1)
- [(1.8)](#exec.counting.scopes.general-1.8)
*open-and-joining*:
when the operation state op is started
while scope is in the *unused* or *open* state,scope moves to the *open-and-joining* state[.](#exec.counting.scopes.general-1.8.sentence-1)
- [(1.9)](#exec.counting.scopes.general-1.9)
*closed*:
when scope.close() is called
while scope is in the *open* state,scope moves to the *closed* state[.](#exec.counting.scopes.general-1.9.sentence-1)
- [(1.10)](#exec.counting.scopes.general-1.10)
*unused-and-closed*:
when scope.close() is called
while scope is in the *unused* state,scope moves to the *unused-and-closed* state[.](#exec.counting.scopes.general-1.10.sentence-1)
- [(1.11)](#exec.counting.scopes.general-1.11)
*closed-and-joining*:
when scope.close() is called
while scope is in the *open-and-joining* state or
the operation state op is started
while scope is in
the *closed* or *unused-and-closed* state,scope moves to the *closed-and-joining* state[.](#exec.counting.scopes.general-1.11.sentence-1)
- [(1.12)](#exec.counting.scopes.general-1.12)
*joined*:
when the count of associations drops to zero
while scope is in
the *open-and-joining* or *closed-and-joining* state,scope moves to the *joined* state[.](#exec.counting.scopes.general-1.12.sentence-1)
[2](#exec.counting.scopes.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7836)
*Recommended practice*: For simple_counting_scope and counting_scope,
implementations should store the state and the count of associations
in a single member of type size_t[.](#exec.counting.scopes.general-2.sentence-1)
[3](#exec.counting.scopes.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7842)
Subclause [[exec.counting.scopes]](#exec.counting.scopes "33.14.2Counting Scopes") makes use of
the following exposition-only entities:
struct *scope-join-t* {}; // *exposition only*enum *scope-state-type* { // *exposition only**unused*, // *exposition only**open*, // *exposition only**closed*, // *exposition only**open-and-joining*, // *exposition only**closed-and-joining*, // *exposition only**unused-and-closed*, // *exposition only**joined*, // *exposition only*};
[4](#exec.counting.scopes.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7860)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for *scope-join-t* as follows:
namespace std::execution {template<>struct *impls-for*<*scope-join-t*> : *default-impls* {template<class Scope, class Rcvr>struct *state* { // *exposition only*struct *rcvr-t* { // *exposition only*using receiver_concept = receiver_t;
Rcvr& *rcvr*; // *exposition only*void set_value() && noexcept { execution::set_value(std::move(*rcvr*)); }template<class E>void set_error(E&& e) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<E>(e)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return execution::get_env(*rcvr*); }}; using *sched-sender* = // *exposition only*decltype(schedule(get_scheduler(get_env(declval<Rcvr&>())))); using *op-t* = // *exposition only* connect_result_t<*sched-sender*, *rcvr-t*>;
Scope* *scope*; // *exposition only* Rcvr& *receiver*; // *exposition only**op-t* *op*; // *exposition only**state*(Scope* scope, Rcvr& rcvr) // *exposition only*noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2Header <functional> synopsis[functional.syn]")<connect_t, *sched-sender*, *rcvr-t*>): *scope*(scope), *receiver*(rcvr), *op*(connect(schedule(get_scheduler(get_env(rcvr))), *rcvr-t*(rcvr))) {}void *complete*() noexcept { // *exposition only* start(*op*); }void *complete-inline*() noexcept { // *exposition only* set_value(std::move(*receiver*)); }}; static constexpr auto *get-state* = // *exposition only*[]<class Rcvr>(auto&& sender, Rcvr& receiver)noexcept(is_nothrow_constructible_v<*state*<Rcvr>, *data-type*<decltype(sender)>, Rcvr&>) {auto[_, self] = sender; return *state*(self, receiver); }; static constexpr auto *start* = // *exposition only*[](auto& s, auto&) noexcept {if (s.*scope*->*start-join-sender*(s)) s.*complete-inline*(); }; };}
#### [33.14.2.2](#simple.counting) Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting)
#### [33.14.2.2.1](#simple.counting.general) General [[exec.scope.simple.counting.general]](exec.scope.simple.counting.general)
[🔗](#lib:execution::simple_counting_scope)
namespace std::execution {class simple_counting_scope {public:// [[exec.simple.counting.token]](#exec.simple.counting.token "33.14.2.2.4Token"), tokenstruct token; static constexpr size_t max_associations = *implementation-defined*; // [[exec.simple.counting.ctor]](#exec.simple.counting.ctor "33.14.2.2.2Constructor and Destructor"), constructor and destructor simple_counting_scope() noexcept;
simple_counting_scope(simple_counting_scope&&) = delete; ~simple_counting_scope(); // [[exec.simple.counting.mem]](#exec.simple.counting.mem "33.14.2.2.3Members"), members token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") auto join() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
[1](#simple.counting.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7971)
For purposes of determining the existence of a data race,get_token,close,join,*try-associate*,*disassociate*, and*start-join-sender* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#simple.counting.general-1.sentence-1)
These operations on a single object of
type simple_counting_scope appear to occur in a single total order[.](#simple.counting.general-1.sentence-2)
#### [33.14.2.2.2](#exec.simple.counting.ctor) Constructor and Destructor [[exec.simple.counting.ctor]](exec.simple.counting.ctor)
[🔗](#lib:execution::simple_counting_scope,constructor)
`simple_counting_scope() noexcept;
`
[1](#exec.simple.counting.ctor-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7991)
*Postconditions*: *count* is 0 and *state* is *unused*[.](#exec.simple.counting.ctor-1.sentence-1)
[🔗](#lib:execution::simple_counting_scope,destructor)
`~simple_counting_scope();
`
[2](#exec.simple.counting.ctor-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8002)
*Effects*: If *state* is not one of*joined*, *unused*, or *unused-and-closed*,
invokes terminate ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#exec.simple.counting.ctor-2.sentence-1)
Otherwise, has no effects[.](#exec.simple.counting.ctor-2.sentence-2)
#### [33.14.2.2.3](#exec.simple.counting.mem) Members [[exec.simple.counting.mem]](exec.simple.counting.mem)
[🔗](#lib:get_token,execution::simple_counting_scope)
`token get_token() noexcept;
`
[1](#exec.simple.counting.mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8018)
*Returns*: An object t of type simple_counting_scope::token such thatt.*scope* == this is true[.](#exec.simple.counting.mem-1.sentence-1)
[🔗](#lib:close,execution::simple_counting_scope)
`void close() noexcept;
`
[2](#exec.simple.counting.mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8030)
*Effects*: If *state* is
- [(2.1)](#exec.simple.counting.mem-2.1)
*unused*, then changes *state* to *unused-and-closed*;
- [(2.2)](#exec.simple.counting.mem-2.2)
*open*, then changes *state* to *closed*;
- [(2.3)](#exec.simple.counting.mem-2.3)
*open-and-joining*,
then changes *state* to *closed-and-joining*;
- [(2.4)](#exec.simple.counting.mem-2.4)
otherwise, no effects[.](#exec.simple.counting.mem-2.sentence-1)
[3](#exec.simple.counting.mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8045)
*Postconditions*: Any subsequent call to *try-associate*() on *this returns false[.](#exec.simple.counting.mem-3.sentence-1)
[🔗](#lib:join,execution::simple_counting_scope)
`[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") auto join() noexcept;
`
[4](#exec.simple.counting.mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8057)
*Returns*: *make-sender*(*scope-join-t*(), this)[.](#exec.simple.counting.mem-4.sentence-1)
[🔗](#lib:try-associate,execution::simple_counting_scope)
`bool try-associate() noexcept;
`
[5](#exec.simple.counting.mem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8068)
*Effects*: If *count* is equal to max_associations, then no effects[.](#exec.simple.counting.mem-5.sentence-1)
Otherwise, if *state* is
- [(5.1)](#exec.simple.counting.mem-5.1)
*unused*,
then increments *count* and changes *state* to *open*;
- [(5.2)](#exec.simple.counting.mem-5.2)
*open* or *open-and-joining*,
then increments *count*;
- [(5.3)](#exec.simple.counting.mem-5.3)
otherwise, no effects[.](#exec.simple.counting.mem-5.sentence-2)
[6](#exec.simple.counting.mem-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8083)
*Returns*: true if *count* was incremented, false otherwise[.](#exec.simple.counting.mem-6.sentence-1)
[🔗](#lib:disassociate,execution::simple_counting_scope)
`void disassociate() noexcept;
`
[7](#exec.simple.counting.mem-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8094)
*Preconditions*: *count* is greater than zero[.](#exec.simple.counting.mem-7.sentence-1)
[8](#exec.simple.counting.mem-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8098)
*Effects*: Decrements *count*[.](#exec.simple.counting.mem-8.sentence-1)
If *count* is zero after decrementing and*state* is *open-and-joining* or *closed-and-joining*,
changes *state* to *joined* and
calls *complete*() on all objects registered with *this[.](#exec.simple.counting.mem-8.sentence-2)
[*Note [1](#exec.simple.counting.mem-note-1)*:
Calling *complete*() on any registered object
can cause *this to be destroyed[.](#exec.simple.counting.mem-8.sentence-3)
— *end note*]
[🔗](#lib:start-join-sender,execution::simple_counting_scope)
`template<class State>
bool start-join-sender(State& st) noexcept;
`
[9](#exec.simple.counting.mem-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8118)
*Effects*: If *state* is
- [(9.1)](#exec.simple.counting.mem-9.1)
*unused*, *unused-and-closed*, or *joined*, then
changes *state* to *joined* and returns true;
- [(9.2)](#exec.simple.counting.mem-9.2)
*open* or *open-and-joining*, then
changes *state* to *open-and-joining*,
registers st with *this and returns false;
- [(9.3)](#exec.simple.counting.mem-9.3)
*closed* or *closed-and-joining*, then
changes *state* to *closed-and-joining*,
registers st with *this and returns false[.](#exec.simple.counting.mem-9.sentence-1)
#### [33.14.2.2.4](#exec.simple.counting.token) Token [[exec.simple.counting.token]](exec.simple.counting.token)
[🔗](#lib:execution::simple_counting_scope::token)
namespace std::execution {struct simple_counting_scope::token {template<[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender> Sender&& wrap(Sender&& snd) const noexcept; bool try_associate() const noexcept; void disassociate() const noexcept; private: simple_counting_scope* *scope*; // *exposition only*};}
[🔗](#lib:wrap,execution::simple_counting_scope::token)
`template<[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>
Sender&& wrap(Sender&& snd) const noexcept;
`
[1](#exec.simple.counting.token-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8160)
*Returns*: std::forward<Sender>(snd)[.](#exec.simple.counting.token-1.sentence-1)
[🔗](#lib:try_associate,execution::simple_counting_scope::token)
`bool try_associate() const noexcept;
`
[2](#exec.simple.counting.token-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8171)
*Effects*: Equivalent to: return *scope*->*try-associate*();
[🔗](#lib:disassociate,execution::simple_counting_scope::token)
`void disassociate() const noexcept;
`
[3](#exec.simple.counting.token-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8182)
*Effects*: Equivalent to *scope*->*disassociate*()[.](#exec.simple.counting.token-3.sentence-1)
#### [33.14.2.3](#counting) Counting Scope [[exec.scope.counting]](exec.scope.counting)
[🔗](#lib:execution::counting_scope)
namespace std::execution {class counting_scope {public:struct token {template<[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") auto wrap(Sender&& snd) const noexcept(*see below*); bool try_associate() const noexcept; void disassociate() const noexcept; private: counting_scope* *scope*; // *exposition only*}; static constexpr size_t max_associations = *implementation-defined*;
counting_scope() noexcept;
counting_scope(counting_scope&&) = delete; ~counting_scope();
token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") auto join() noexcept; void request_stop() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only* inplace_stop_source *s_source*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
[1](#counting-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8230)
counting_scope differs from simple_counting_scope by
adding support for cancellation[.](#counting-1.sentence-1)
Unless specified below, the semantics of members of counting_scope are the same as the corresponding members of simple_counting_scope[.](#counting-1.sentence-2)
[🔗](#lib:get_token,execution::counting_scope)
`token get_token() noexcept;
`
[2](#counting-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8242)
*Returns*: An object t of type counting_scope::token such thatt.*scope* == this is true[.](#counting-2.sentence-1)
[🔗](#lib:request_stop,execution::counting_scope)
`void request_stop() noexcept;
`
[3](#counting-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8254)
*Effects*: Equivalent to *s_source*.request_stop()[.](#counting-3.sentence-1)
[4](#counting-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8258)
*Remarks*: Calls to request_stop do not introduce data races[.](#counting-4.sentence-1)
[🔗](#lib:wrap,execution::counting_scope::token)
`template<[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>
[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") auto counting_scope::token::wrap(Sender&& snd) const
noexcept(is_nothrow_constructible_v<remove_cvref_t<Sender>, Sender>);
`
[5](#counting-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8271)
*Effects*: Equivalent to:return *stop-when*(std::forward<Sender>(snd), *scope*->*s_source*.get_token());