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

369 lines
16 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.consumers]
# 33 Execution control library [[exec]](./#exec)
## 33.9 Senders [[exec.snd]](exec.snd#exec.consumers)
### 33.9.13 Sender consumers [exec.consumers]
#### [33.9.13.1](#exec.sync.wait) this_thread::sync_wait [[exec.sync.wait]](exec.sync.wait)
[1](#exec.sync.wait-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5595)
this_thread::sync_wait and this_thread::sync_wait_with_variant are used
to block the current thread of execution
until the specified sender completes and
to return its async result[.](#exec.sync.wait-1.sentence-1)
sync_wait mandates
that the input sender has exactly one value completion signature[.](#exec.sync.wait-1.sentence-2)
[2](#exec.sync.wait-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5604)
Let *sync-wait-env* be the following exposition-only class type:namespace std::this_thread {struct *sync-wait-env* { execution::run_loop* *loop*; // *exposition only*auto query(execution::get_scheduler_t) const noexcept {return *loop*->get_scheduler(); }auto query(execution::get_delegation_scheduler_t) const noexcept {return *loop*->get_scheduler(); }};}
[3](#exec.sync.wait-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5622)
Let *sync-wait-result-type* and*sync-wait-with-variant-result-type* be exposition-only alias templates defined as follows:namespace std::this_thread {template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*, *decayed-tuple*,
type_identity_t>>; template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-with-variant-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*>>;}
[4](#exec.sync.wait-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5639)
The name this_thread::sync_wait denotes a customization point object[.](#exec.sync.wait-4.sentence-1)
For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.sync.wait-4.sentence-2)
The expression this_thread::sync_wait(sndr) is expression-equivalent to the following,
except that sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait, sndr)*Mandates*:
- [(4.1)](#exec.sync.wait-4.1)
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#exec.sync.wait-4.1.sentence-1)
- [(4.2)](#exec.sync.wait-4.2)
The type *sync-wait-result-type*<Sndr> is well-formed[.](#exec.sync.wait-4.2.sentence-1)
- [(4.3)](#exec.sync.wait-4.3)
[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(e), *sync-wait-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#exec.sync.wait-4.3.sentence-1)
[5](#exec.sync.wait-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5659)
Let *sync-wait-state* and *sync-wait-receiver* be the following exposition-only class templates:namespace std::this_thread {template<class Sndr>struct *sync-wait-state* { // *exposition only* execution::run_loop *loop*; // *exposition only* exception_ptr *error*; // *exposition only**sync-wait-result-type*<Sndr> *result*; // *exposition only*}; template<class Sndr>struct *sync-wait-receiver* { // *exposition only*using receiver_concept = execution::receiver_t; *sync-wait-state*<Sndr>* *state*; // *exposition only*template<class... Args>void set_value(Args&&... args) && noexcept; template<class Error>void set_error(Error&& err) && noexcept; void set_stopped() && noexcept; *sync-wait-env* get_env() const noexcept { return {&*state*->*loop*}; }};}
[🔗](#exec.sync.wait-itemdecl:1)
`template<class... Args>
void set_value(Args&&... args) && noexcept;
`
[6](#exec.sync.wait-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5695)
*Effects*: Equivalent to:try {*state*->*result*.emplace(std::forward<Args>(args)...);} catch (...) {*state*->*error* = current_exception();}*state*->*loop*.finish();
[🔗](#exec.sync.wait-itemdecl:2)
`template<class Error>
void set_error(Error&& err) && noexcept;
`
[7](#exec.sync.wait-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5714)
*Effects*: Equivalent to:*state*->*error* = *AS-EXCEPT-PTR*(std::forward<Error>(err)); // see [[exec.general]](exec.general "33.1General")*state*->*loop*.finish();
[🔗](#exec.sync.wait-itemdecl:3)
`void set_stopped() && noexcept;
`
[8](#exec.sync.wait-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5728)
*Effects*: Equivalent to *state*->*loop*.finish()[.](#exec.sync.wait-8.sentence-1)
[9](#exec.sync.wait-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5733)
For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.sync.wait-9.sentence-1)
If [sender_to](exec.snd.concepts#concept:sender_to "33.9.3Sender concepts[exec.snd.concepts]")<Sndr, *sync-wait-receiver*<Sndr>> is false,
the expression sync_wait.apply_sender(sndr) is ill-formed;
otherwise, it is equivalent to:*sync-wait-state*<Sndr> state;auto op = connect(sndr, *sync-wait-receiver*<Sndr>{&state});
start(op);
state.*loop*.run();if (state.*error*) { rethrow_exception(std::move(state.*error*));}return std::move(state.*result*);
[10](#exec.sync.wait-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5751)
The behavior of this_thread::sync_wait(sndr) is undefined unless:
- [(10.1)](#exec.sync.wait-10.1)
It blocks the current thread of execution ([[defns.block]](defns.block "3.6block"))
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3Forward progress"))
until the specified sender completes[.](#exec.sync.wait-10.1.sentence-1)
[*Note [1](#exec.sync.wait-note-1)*:
The default implementation of sync_wait achieves
forward progress guarantee delegation by providing a run_loop scheduler
via the get_delegation_scheduler query
on the *sync-wait-receiver*'s environment[.](#exec.sync.wait-10.1.sentence-2)
The run_loop is driven by the current thread of execution[.](#exec.sync.wait-10.1.sentence-3)
— *end note*]
- [(10.2)](#exec.sync.wait-10.2)
It returns the specified sender's async results as follows:
* [(10.2.1)](#exec.sync.wait-10.2.1)
For a value completion,
the result datums are returned in
a tuple in an engaged optional object[.](#exec.sync.wait-10.2.1.sentence-1)
* [(10.2.2)](#exec.sync.wait-10.2.2)
For an error completion, an exception is thrown[.](#exec.sync.wait-10.2.2.sentence-1)
* [(10.2.3)](#exec.sync.wait-10.2.3)
For a stopped completion, a disengaged optional object is returned[.](#exec.sync.wait-10.2.3.sentence-1)
#### [33.9.13.2](#exec.sync.wait.var) this_thread::sync_wait_with_variant [[exec.sync.wait.var]](exec.sync.wait.var)
[1](#exec.sync.wait.var-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5781)
The name this_thread::sync_wait_with_variant denotes
a customization point object[.](#exec.sync.wait.var-1.sentence-1)
For a subexpression sndr,
let Sndr be decltype(into_variant(sndr))[.](#exec.sync.wait.var-1.sentence-2)
The expression this_thread::sync_wait_with_variant(sndr) is expression-equivalent to the following,
except sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait_with_variant, sndr)*Mandates*:
- [(1.1)](#exec.sync.wait.var-1.1)
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3Sender concepts[exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#exec.sync.wait.var-1.1.sentence-1)
- [(1.2)](#exec.sync.wait.var-1.2)
The type *sync-wait-with-variant-result-type*<Sndr> is well-formed[.](#exec.sync.wait.var-1.2.sentence-1)
- [(1.3)](#exec.sync.wait.var-1.3)
[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(e), *sync-wait-with-variant-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#exec.sync.wait.var-1.3.sentence-1)
[2](#exec.sync.wait.var-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5804)
The expression sync_wait_with_variant.apply_sender(sndr) is equivalent to:using result_type = *sync-wait-with-variant-result-type*<Sndr>;if (auto opt_value = sync_wait(into_variant(sndr))) {return result_type(std::move(get<0>(*opt_value)));}return result_type(nullopt);
[3](#exec.sync.wait.var-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5814)
The behavior of this_thread::sync_wait_with_variant(sndr) is undefined unless:
- [(3.1)](#exec.sync.wait.var-3.1)
It blocks the current thread of execution ([[defns.block]](defns.block "3.6block"))
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3Forward progress"))
until the specified sender completes[.](#exec.sync.wait.var-3.1.sentence-1)
[*Note [1](#exec.sync.wait.var-note-1)*:
The default implementation of sync_wait_with_variant achieves
forward progress guarantee delegation by relying on
the forward progress guarantee delegation provided by sync_wait[.](#exec.sync.wait.var-3.1.sentence-2)
— *end note*]
- [(3.2)](#exec.sync.wait.var-3.2)
It returns the specified sender's async results as follows:
* [(3.2.1)](#exec.sync.wait.var-3.2.1)
For a value completion,
the result datums are returned in an engaged optional object
that contains a variant of tuples[.](#exec.sync.wait.var-3.2.1.sentence-1)
* [(3.2.2)](#exec.sync.wait.var-3.2.2)
For an error completion, an exception is thrown[.](#exec.sync.wait.var-3.2.2.sentence-1)
* [(3.2.3)](#exec.sync.wait.var-3.2.3)
For a stopped completion, a disengaged optional object is returned[.](#exec.sync.wait.var-3.2.3.sentence-1)
#### [33.9.13.3](#exec.spawn) execution::spawn [[exec.spawn]](exec.spawn)
[1](#exec.spawn-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5843)
spawn attempts to associate the given input sender with
the given token's async scope and, on success,
eagerly starts the input sender[.](#exec.spawn-1.sentence-1)
[2](#exec.spawn-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5848)
The name spawn denotes a customization point object[.](#exec.spawn-2.sentence-1)
For subexpressions sndr, token, and env,
- [(2.1)](#exec.spawn-2.1)
let Sndr be decltype((sndr)),
- [(2.2)](#exec.spawn-2.2)
let Token be remove_cvref_t<decltype((token))>, and
- [(2.3)](#exec.spawn-2.3)
let Env be remove_cvref_t<decltype((env))>[.](#exec.spawn-2.sentence-2)
If any of[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2queryable concept[exec.queryable.concept]")<Env> are not satisfied,
the expression spawn(sndr, token, env) is ill-formed[.](#exec.spawn-2.sentence-3)
[3](#exec.spawn-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5863)
Let *spawn-state-base* be the exposition-only class:
[🔗](#lib:execution::spawn-state-base)
namespace std::execution {struct *spawn-state-base* { // *exposition only*virtual void *complete*() noexcept = 0; // *exposition only*};}
[4](#exec.spawn-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5875)
Let *spawn-receiver* be the exposition-only class:
[🔗](#lib:execution::spawn-receiver)
namespace std::execution {struct *spawn-receiver* { // *exposition only*using receiver_concept = receiver_t; *spawn-state-base** *state*; // *exposition only*void set_value() && noexcept { *state*->*complete*(); }void set_stopped() && noexcept { *state*->*complete*(); }};}
[5](#exec.spawn-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5891)
Let *spawn-state* be the exposition-only class template:
[🔗](#lib:execution::spawn-state)
namespace std::execution {template<class Alloc, [scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>struct *spawn-state* : *spawn-state-base* { // *exposition only*using *op-t* = connect_result_t<Sender, *spawn-receiver*>; // *exposition only**spawn-state*(Alloc alloc, Sender&& sndr, Token token); // *exposition only*void *complete*() noexcept override; // *exposition only*void *run*(); // *exposition only*private:using *alloc-t* = // *exposition only*typename allocator_traits<Alloc>::template rebind_alloc<*spawn-state*>; *alloc-t* *alloc*; // *exposition only**op-t* *op*; // *exposition only* Token *token*; // *exposition only*void *destroy*() noexcept; // *exposition only*};}
[🔗](#lib:execution::spawn-state,constructor)
`spawn-state(Alloc alloc, Sender&& sndr, Token token);
`
[6](#exec.spawn-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5924)
*Effects*: Initializes*alloc* with alloc,*token* with token, and*op* with:connect(std::move(sndr), *spawn-receiver*(this))
[🔗](#lib:run,execution::spawn-state)
`void run();
`
[7](#exec.spawn-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5941)
*Effects*: Equivalent to:if (*token*.try_associate()) start(*op*);else*destroy*();
[🔗](#lib:complete,execution::spawn-state)
`void complete() noexcept override;
`
[8](#exec.spawn-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5958)
*Effects*: Equivalent to:auto token = std::move(this->*token*);
*destroy*();
token.disassociate();
[🔗](#lib:destroy,execution::spawn-state)
`void destroy() noexcept;
`
[9](#exec.spawn-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5975)
*Effects*: Equivalent to:auto alloc = std::move(this->*alloc*);
allocator_traits<*alloc-t*>::destroy(alloc, this);
allocator_traits<*alloc-t*>::deallocate(alloc, this, 1);
[10](#exec.spawn-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5986)
For the expression spawn(sndr, token, env) let new_sender be the expression token.wrap(sndr) and
let alloc and senv be defined as follows:
- [(10.1)](#exec.spawn-10.1)
if the expression get_allocator(env) is well-formed, thenalloc is the result of get_allocator(env) andsenv is the expression env,
- [(10.2)](#exec.spawn-10.2)
otherwise
if the expression get_allocator(get_env(new_sender)) is well-formed, thenalloc is the result of get_allocator(get_env(new_sender)) andsenv is the expression *JOIN-ENV*(prop(get_allocator, alloc), env),
- [(10.3)](#exec.spawn-10.3)
otherwisealloc is allocator<void>() andsenv is the expression env[.](#exec.spawn-10.sentence-1)
[11](#exec.spawn-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6006)
The expression spawn(sndr, token, env) is of type void and
has the following effects:
- [(11.1)](#exec.spawn-11.1)
Uses alloc to allocate and construct an object o of
type that is a specialization of *spawn-state* fromalloc, write_env(token.wrap(sndr), senv), and token and then
invokes o.*run*()[.](#exec.spawn-11.sentence-1)
If an exception is thrown then
any constructed objects are destroyed and any allocated memory is deallocated[.](#exec.spawn-11.1.sentence-2)
[12](#exec.spawn-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6021)
The expression spawn(sndr, token) is expression-equivalent tospawn(sndr, token, execution::env<>())[.](#exec.spawn-12.sentence-1)