33 Execution control library [exec]

33.3 Asynchronous operations [exec.async.ops]

An execution resource is a program entity that manages a (possibly dynamic) set of execution agents ([thread.req.lockable.general]), which it uses to execute parallel work on behalf of callers.
[Example 1: 
The currently active thread, a system-provided thread pool, and uses of an API associated with an external hardware accelerator are all examples of execution resources.
— end example]
Execution resources execute asynchronous operations.
An execution resource is either valid or invalid.
An asynchronous operation is a distinct unit of program execution that
  • is explicitly created;
  • can be explicitly started once at most;
  • once started, eventually completes exactly once with a (possibly empty) set of result datums and in exactly one of three dispositions: success, failure, or cancellation;
    An asynchronous operation's async result is its disposition and its (possibly empty) set of result datums.
  • can complete on a different execution resource than the execution resource on which it started; and
  • can create and start other asynchronous operations called child operations.
    A child operation is an asynchronous operation that is created by the parent operation and, if started, completes before the parent operation completes.
    A parent operation is the asynchronous operation that created a particular child operation.
[Note 1: 
An asynchronous operation can execute synchronously; that is, it can complete during the execution of its start operation on the thread of execution that started it.
— end note]
An asynchronous operation has associated state known as its operation state.
An asynchronous operation has an associated environment.
An environment is a queryable object ([exec.queryable]) representing the execution-time properties of the operation's caller.
The caller of an asynchronous operation is its parent operation or the function that created it.
An asynchronous operation's operation state owns the operation's environment.
An asynchronous operation has an associated receiver.
A receiver is an aggregation of three handlers for the three asynchronous completion dispositions:
  • a value completion handler for a value completion,
  • an error completion handler for an error completion, and
  • a stopped completion handler for a stopped completion.
A receiver has an associated environment.
An asynchronous operation's operation state owns the operation's receiver.
The environment of an asynchronous operation is equal to its receiver's environment.
For each completion disposition, there is a completion function.
A completion function is a customization point object ([customization.point.object]) that accepts an asynchronous operation's receiver as the first argument and the result datums of the asynchronous operation as additional arguments.
The value completion function invokes the receiver's value completion handler with the value result datums; likewise for the error completion function and the stopped completion function.
A completion function has an associated type known as its completion tag that is the unqualified type of the completion function.
A valid invocation of a completion function is called a completion operation.
The lifetime of an asynchronous operation, also known as the operation's async lifetime, begins when its start operation begins executing and ends when its completion operation begins executing.
If the lifetime of an asynchronous operation's associated operation state ends before the lifetime of the asynchronous operation, the behavior is undefined.
After an asynchronous operation executes a completion operation, its associated operation state is invalid.
Accessing any part of an invalid operation state is undefined behavior.
An asynchronous operation shall not execute a completion operation before its start operation has begun executing.
After its start operation has begun executing, exactly one completion operation shall execute.
The lifetime of an asynchronous operation's operation state can end during the execution of the completion operation.
A sender is a factory for one or more asynchronous operations.
Connecting a sender and a receiver creates an asynchronous operation.
The asynchronous operation's associated receiver is equal to the receiver used to create it, and its associated environment is equal to the environment associated with the receiver used to create it.
The lifetime of an asynchronous operation's associated operation state does not depend on the lifetimes of either the sender or the receiver from which it was created.
A sender is started when it is connected to a receiver and the resulting asynchronous operation is started.
A sender's async result is the async result of the asynchronous operation created by connecting it to a receiver.
A sender sends its results by way of the asynchronous operation(s) it produces, and a receiver receives those results.
A sender is either valid or invalid; it becomes invalid when its parent sender (see below) becomes invalid.
A scheduler is an abstraction of an execution resource with a uniform, generic interface for scheduling work onto that resource.
It is a factory for senders whose asynchronous operations execute value completion operations on an execution agent belonging to the scheduler's associated execution resource.
A schedule-expression obtains such a sender from a scheduler.
A schedule sender is the result of a schedule expression.
On success, an asynchronous operation produced by a schedule sender executes a value completion operation with an empty set of result datums.
Multiple schedulers can refer to the same execution resource.
A scheduler can be valid or invalid.
A scheduler becomes invalid when the execution resource to which it refers becomes invalid, as do any schedule senders obtained from the scheduler, and any operation states obtained from those senders.
An asynchronous operation has one or more associated completion schedulers for each of its possible dispositions.
A completion scheduler is a scheduler whose associated execution resource is used to execute a completion operation for an asynchronous operation.
A value completion scheduler is a scheduler on which an asynchronous operation's value completion operation can execute.
Likewise for error completion schedulers and stopped completion schedulers.
A sender has an associated queryable object ([exec.queryable]) known as its attributes that describes various characteristics of the sender and of the asynchronous operation(s) it produces.
For each disposition, there is a query object for reading the associated completion scheduler from a sender's attributes; i.e., a value completion scheduler query object for reading a sender's value completion scheduler, etc.
If a completion scheduler query is well-formed, the returned completion scheduler is unique for that disposition for any asynchronous operation the sender creates.
A schedule sender is required to have a value completion scheduler attribute whose value is equal to the scheduler that produced the schedule sender.
A completion signature is a function type that describes a completion operation.
An asynchronous operation has a finite set of possible completion signatures corresponding to the completion operations that the asynchronous operation potentially evaluates ([basic.def.odr]).
For a completion function set, receiver rcvr, and pack of arguments args, let c be the completion operation set(rcvr, args...), and let F be the function type decltype(auto(set))(decltype((args))...).
A completion signature Sig is associated with c if and only if MATCHING-SIG(Sig, F) is true ([exec.general])).
Together, a sender type and an environment type Env determine the set of completion signatures of an asynchronous operation that results from connecting the sender with a receiver that has an environment of type Env.
The type of the receiver does not affect an asynchronous operation's completion signatures, only the type of the receiver's environment.
A sender algorithm is a function that takes and/or returns a sender.
There are three categories of sender algorithms:
  • A sender factory is a function that takes non-senders as arguments and that returns a sender.
  • A sender adaptor is a function that constructs and returns a parent sender from a set of one or more child senders and a (possibly empty) set of additional arguments.
    An asynchronous operation created by a parent sender is a parent operation to the child operations created by the child senders.
  • A sender consumer is a function that takes one or more senders and a (possibly empty) set of additional arguments, and whose return type is not the type of a sender.