[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.3 Sender 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.3 Sender 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.3 Sender 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.2 Concept 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.1 General")*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.3 Sender 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.6 block"))
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward 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.3 Sender 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.2 Concept 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.6 block"))
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward 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.3 Sender concepts [exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable 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.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender 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)
