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
startis called on an operation state. - Once started, the operation states 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 queryable object for the scheduler an operation will be or was 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 scheduler the operation was started on (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) |
adapts a sender so that the operations inside it see extra or different values in their execution environment (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 sender to run it (or a continuation of it) on the provided scheduler, then return to the scheduler it came from (customization point object) |
(C++26) |
a customization hook for how work leaves a scheduler's execution context (completes like the sender it wraps) (customization point object) |
(C++26) |
chains a function onto a sender, calling it with the values the sender sends and sending its result on (customization point object) |
(C++26) |
chains a function onto a sender, calling it with the error if the sender fails and sending its result on as a value (customization point object) |
(C++26) |
chains a function onto a sender, calling it if the sender is cancelled and sending its result on as a value (customization point object) |
(C++26) |
chains a function onto a sender, calling it with the values the sender sends and continuing with the sender it returns (customization point object) |
(C++26) |
chains a function onto a sender, calling it with the error if the sender fails and continuing with the sender it returns (customization point object) |
(C++26) |
chains a function onto a sender, calling it if the sender is cancelled and continuing with the sender it returns (customization point object) |
| runs a function for every index in a range after a sender completes, so the work can be spread over a scheduler's execution resources (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) |
adapts a sender that can complete with several different sets of values into one that completes with a single std::variant of tuples (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 launches the given sender within an asynchronous scope, returning immediately without waiting for it to finish (customization point object) |
Notes
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_lib_counting_scope |
202506L |
(C++26) | Async scopes: creating scopes for non-sequential concurrency |
__cpp_lib_parallel_scheduler |
202506L |
(C++26) | Parallel scheduler |
__cpp_lib_senders |
202406L |
(C++26) | std::execution: Sender-receiver model of execution control |
202506L |
(C++26) | std::execution: More extensions | |
__cpp_lib_task |
202506L |
(C++26) | Coroutine task types |
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. | What are Senders Good For, Anyway? Eric Niebler, 2024 |