Execution control library (since C++26)
The Execution control library provides a framework for managing asynchronous execution on generic execution resources.
The library aims to provide vocabulary types for asynchronous operations and to allow the construction of task execution graphs in a simple, composable way.
Library-wide definitions
- Sender: A description of asynchronous work to be sent for execution. Produces an operation state (below).
- Senders asynchronously “send” their results to listeners called “receivers” (below).
- Senders can be composed into task graphs using generic algorithms.
- Sender factories and adaptors are generic algorithms that capture common async patterns in objects satisfying the sender concept.
- A sender has an associated “queryable object” (below) known as sender attributes that describes various characteristics of the sender and of the asynchronous operation(s) it produces.
- Receiver: A generalized callback that consumes or “receives” the asynchronous results produced by a sender.
- Receivers have three different “channels” through which a sender may propagate results: success, failure, and canceled, so-named “value”, “error”, and “stopped”.
- Receivers provide an extensible execution environment: a “queryable object” (below) that the consumer can use to parameterize the asynchronous operation.
- Operation State: An object that contains the state needed by the asynchronous operation.
- A sender and receiver are connected when passed to the std::execution::connect function.
- The result of connecting a sender and a receiver is an operation state.
- Work is not enqueued for execution until “
start” is called on an operation state. - Once started, the operation state’s lifetime cannot end before the async operation is complete, and its address must be stable.
- Execution Agent: An entity such as a thread that may perform work in parallel with other execution agents
- Implementations or users can introduce other kinds of agents such as processes or thread-pool tasks.
- Execution Resource: Also known as execution context, a program entity that manages a (possibly dynamic) set of execution agents.
- 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.
- Scheduler: A lightweight handle to an execution resource for scheduling work onto that resource.
- A scheduler is a factory for a sender that completes its receiver from an execution agent owned by the execution resource.
- Queryable Object: A read-only collection of key/value pair where each key is a customization point object known as a “query object”.
- A query is an invocation of a query object with a queryable object as its first argument and a (possibly empty) set of additional arguments. A query imposes syntactic and semantic requirements on its invocations.
Library utilities
Concepts
Schedulers
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is a scheduler (concept) |
Senders
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is a sender (concept) |
(C++26) |
specifies a sender that can create asynchronous operations for given associated environment type (concept) |
(C++26) |
specifies the requirements for a sender type whose completion signatures cannot be determined independently of its execution environment (concept) |
Receivers
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is a receiver (concept) |
| specifies the requirements for a receiver that can be reconstructed on demand from a pointer to the operation state object created when the receiver was connected to a sender (concept) | |
Operation states
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is an operation state (concept) |
Asynchronous scopes
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies the requirements for an RAII handle that represents an active association with an asynchronous scope (concept) |
(C++26) |
specifies a non-owning handle to an asynchronous scope that behaves like a reference to asynchronous scope (concept) |
Utility components
Execution contexts
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
execution resource holding a thread-safe MPSC task queue and a manually-driven event loop (class) |
Execution domains
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
default execution domain tag type that dispatches transformations from a sender tag (class) |
(C++26) |
transforms into a new sender under a given execution domain tag (function template) |
(C++26) |
consumes a sender using a given sender consumer tag with a set of arguments and returns its result under a given execution domain tag (function template) |
Forward progress guarantee
Defined in header
<execution> | |
Defined in namespace
std::execution | |
| specifies a forward progress guarantee of execution agents created by the scheduler's associated execution resource (enum) | |
Environments
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
builds a queryable object from a query object and a value (class template) |
(C++26) |
aggregates several queryable objects into one queryable object (class template) |
(C++26) |
returns the associated queryable object for its given argument (customization point object) |
Queries
Defined in header
<execution> | |
(C++26) |
asks a query object whether it should be forwarded through queryable adaptors (customization point object) |
(C++26) |
asks a queryable object for its associated allocator (customization point object) |
(C++26) |
asks a queryable object for its associated stop token (customization point object) |
(C++26) |
asks a queryable object for its associated execution domain tag (customization point object) |
| asks the completion domain associated with a completion tag from a sender's attributes (customization point object) | |
(C++26) |
asks a queryable object for its associated scheduler (customization point object) |
| asks a receiver's environment what scheduler an operation state that was created with that receiver will be started on. (customization point object) | |
| asks a queryable object for a scheduler that can be used to delegate work to for the purpose of forward progress delegation (customization point object) | |
| obtains the completion scheduler associated with a completion tag from a sender's attributes (customization point object) | |
| asks a scheduler about its execution::forward_progress_guarantee (customization point object) | |
| asks a queryable object for its associated awaitable completion adaptor (customization point object) | |
Completion signatures
Defined in header
<execution> | |
Defined in namespace
std::execution | |
| type that encodes a set of completion signatures (class template) | |
| obtains the completion signatures of a sender (customization point object) | |
(C++26) |
obtains the tag type of a sender (alias template) |
(C++26) |
obtains the value completion type of a sender (alias template) |
(C++26) |
obtains the error completion type of a sender (alias template) |
(C++26) |
determines whether the sender supports stopped completion (variable template) |
Coroutine utility
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
transforms an expression into awaitable object within a particular coroutine (customization point object) |
| when used as the base class of a coroutine promise type, enables senders to be awaitable within that coroutine type (class template) | |
(C++26) |
adapts a sender into one that completes on the receiver's scheduler. If the algorithm determines that the adapted sender already completes on the correct scheduler it can avoid any scheduling operation (customization point object) |
(C++26) |
a trivial scheduler that completes immediately and synchronously on the thread that calls std::execution::start on the operation state produced by its sender (class) |
(C++26) |
represents a sender that can be used as the return type of coroutine functions (class template) |
(C++26) |
provides a uniform, type-erased interface, which allows to store, pass around, and invoke scheduling operations on arbitrary infallible schedulers (class) |
Asynchronous scopes
Defined in header
<execution> | |
Defined in namespace
std::execution | |
| a lightweight, reference-counted asynchronous scope. It tracks how many dynamically spawned asynchronous operations are currently running (class) | |
(C++26) |
differs from simple_counting_scope by adding support for cancellation (class) |
Parallel scheduler
Defined in header
<execution> | |
Defined in namespace
std::execution | |
| represents a handle of a shared global execution resource (such as a OS-provided system thread pool) optimized for parallel execution (class) | |
returns an instance of parallel_scheduler that represents the shared parallel execution context within the application. successive calls to this function return scheduler objects that reference the same underlying global thread pool (function) | |
Defined in namespace
std::execution::parallel_scheduler_replacement | |
represents a receiver that will be notified by the implementations of parallel_scheduler_backend to trigger the completion operations (class) | |
used for bulk_chunked and bulk_unchunked customizations that will also receive notifications from implementations of parallel_scheduler_backend corresponding to different iterations (class) | |
serves as the abstraction bridge between the user-facing parallel_scheduler and the backend execution resource (such as a OS-provided system thread pool) (class) | |
returns a shared_ptr<parallel_scheduler_backend> that represents the shared parallel execution context within the application. successive calls to this function return shared_ptr that point to the same parallel_scheduler_backend object (function) | |
Core operations
Operation state
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
connects a sender with a receiver (customization point object) |
(C++26) |
starts the asynchronous operation associated with an operation_state object (customization point object) |
Completion functions
These functions are called by senders to announce the completion of the work to their receivers.
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
value completion function indicating successful completion (customization point object) |
(C++26) |
error completion function indicating that an error occurred during calculation or scheduling (customization point object) |
(C++26) |
stopped completion function indicating that an operation ended before it could achieve success or failure (customization point object) |
Sender algorithms
| This section is incomplete Reason: WIP update to current standard in progress |
Sender factories
A sender factory is a function that returns a sender and whose parameters have types for which the sender concept is false.
The following are sender factories:
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
accepts a variadic number of arguments and returns a sender that, when connected and started, completes synchronously by passing the arguments to the receiver's value completion function (customization point object) |
(C++26) |
accepts a single argument and returns a sender that, when connected and started, completes synchronously by passing the argument to the receiver's error completion function (customization point object) |
(C++26) |
creates a sender that completes immediately by calling its receiver's set_stopped(customization point object) |
(C++26) |
creates a sender that queries its receiver's associated environment (customization point object) |
(C++26) |
prepares a task graph for execution on a given scheduler (customization point object) |
Pipeable sender adaptors
Defined in header
<execution> | |
Defined in namespace
std::execution | |
| helper base class template for defining a pipeable sender adaptor closure object (class template) | |
Sender adaptors
A sender adaptor is a function returning a sender whose parameters include at least one whose type satisfies the sender concept, and for which the returned sender is a parent sender of the adaptor function's sender arguments.
The following are sender adaptors:
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
injects values into the environment a provided sender sees — overriding or augmenting what the eventual receiver exposes (customization point object) |
(C++26) |
shields the provided sender from external cancellation requests, ensuring that the critical task runs uninterrupted to completion (customization point object) |
(C++26) |
adapts a provided sender into one that will start an execution on the provided scheduler's execution resource (customization point object) |
(C++26) |
adapts a provided sender into one that completes on the provided scheduler's execution resource (customization point object) |
(C++26) |
adapts a provided sender to transfer execution to a provided scheduler's execution resource on which the sender or the continuation runs, and then transfers execution back to the original resource (customization point object) |
(C++26) |
schedules work dependent on the completion of a provided sender onto a provided scheduler's execution resource (customization point object) |
(C++26) |
chains the task graph by the input sender with a node represents invoking the provided function with the values sent by the input sender as arguments (customization point object) |
(C++26) |
chains the task graph by the input sender with a node representing invoking the provided function with the error sent by the input sender if an error occurred (customization point object) |
(C++26) |
chains the task graph by the input sender with a node representing invoking the provided function with the stopped behavior by the input sender if a "stopped" signal is sent (customization point object) |
(C++26) |
returns a sender which represents a node chained to the input sender, which when started, invokes the provided function with the values sent by the input sender as arguments (customization point object) |
(C++26) |
returns a sender which represents a node chained to the input sender, which invokes the provided function with the error from the input sender, if occurred (customization point object) |
(C++26) |
returns a sender which represents a node chained to the input sender, which invokes the provided function with the stop token from the input sender, if the "stopped" signal is sent (customization point object) |
| creates a multi-shot sender that invokes the function with every index in the provided shape along with the values sent by the input sender. The sender completes once all invocations have completed, or an error has occurred (customization point object) | |
(C++26) |
adapts multiple input senders into a sender that completes once all of the input senders have completed (customization point object) |
| adapts multiple input senders, with each possibly having multiple completion signatures, into a sender that completes once all of the input senders have completed (customization point object) | |
(C++26) |
returns a sender which sends a variant of tuples of all the possible sets of types sent by the input sender (customization point object) |
returns a sender that maps the value channel to std::optional<std::decay_t<T>> and the stopped channel to std::nullopt(customization point object) | |
(C++26) |
returns a sender that maps the stopped channel to an error (customization point object) |
(C++26) |
tries to associate a sender with an asynchronous scope such that the scope can track the lifetime of any asynchronous operations created with the sender (customization point object) |
(C++26) |
attempts to associate the given input sender with an asynchronous scope and, on success, eagerly starts the input sender; the return value is a sender that, when connected and started, completes with either the result of the eagerly-started input sender or with set_stopped if the input sender was not started(customization point object) |
Sender consumers
A sender consumer is an algorithm that takes one or more senders as parameters and that does not return a sender.
Defined in header
<execution> | |
Defined in namespace
std::this_thread | |
(C++26) |
blocks current thread until the specified sender completes and returns its async result (customization point object) |
| blocks current thread until the specified sender with possibly multiple completion signatures completes and returns its async result (customization point object) | |
Defined in namespace
std::execution | |
(C++26) |
eagerly launchs the given sender within an asynchronous scope, returning immediately without waiting for it to finish (customization point object) |
Example
A version of this example is available on godbolt.org, where it uses stdexec, an experimental reference implementation of std::execution.
#include <cstdio>
#include <execution>
#include <string>
#include <thread>
#include <utility>
using namespace std::literals;
int main()
{
std::execution::run_loop loop;
std::jthread worker([&](std::stop_token st)
{
std::stop_callback cb{st, [&]{ loop.finish(); }};
loop.run();
});
std::execution::sender auto hello = std::execution::just("hello world"s);
std::execution::sender auto print
= std::move(hello)
| std::execution::then([](std::string msg)
{
return std::puts(msg.c_str());
});
std::execution::scheduler auto io_thread = loop.get_scheduler();
std::execution::sender auto work = std::execution::on(io_thread, std::move(print));
auto [result] = std::this_thread::sync_wait(std::move(work)).value();
return result;
}
Output:
hello world
See also
(C++11) |
runs a function asynchronously (potentially in a new thread) and returns a std::future that will hold the result (function template) |
External links
| 1. | NVIDIA/stdexec — A reference implementation on github.com
|
| 2. | bemanproject/execution — Another reference implementation on github.com
|
| 3. | Eric Niebler, 2024 - What are Senders Good For, Anyway? |