Difference between revisions of "cpp/execution"
(→Example: add missing headers, write out execution namespace so that the autolinker can theoretically work) |
m (→execution domain: added) |
||
(26 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
− | {{title|Execution library}} | + | {{title|Execution library {{mark since c++26}}}} |
− | {{cpp | + | {{cpp/execution/navbar}} |
− | + | The Execution 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. | |
− | + | ||
− | + | ||
− | + | ||
− | The library aims to provide vocabulary types for | + | |
==Library-wide definitions== | ==Library-wide definitions== | ||
Line 15: | Line 11: | ||
:* Senders asynchronously “send” their results to listeners called “receivers” (below). | :* Senders asynchronously “send” their results to listeners called “receivers” (below). | ||
:* Senders can be composed into '''task graphs''' using generic algorithms. | :* 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. | + | :* '''Sender factories and adaptors''' are generic algorithms that capture common async patterns in objects satisfying the {{lc|sender}}<!--{{lconcept|sender}}--> concept. |
* '''Receiver''': A generalized callback that consumes or “receives” the asynchronous results produced by a sender. | * '''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 have three different “channels” through which a sender may propagate results: success, failure, and canceled, so-named “value”, “error”, and “stopped”. | ||
Line 30: | Line 26: | ||
==Library utilities== | ==Library utilities== | ||
− | ===Senders=== | + | ===Concepts=== |
+ | ====Schedulers==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc scheduler}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Senders==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc sender}} | ||
+ | {{dsc inc|cpp/execution/dsc sender_in}} | ||
+ | {{dsc inc|cpp/execution/dsc sender_to}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Receivers==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc receiver}} | ||
+ | {{dsc inc|cpp/execution/dsc receiver_of}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Operation states==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc operation_state}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Utility components=== | ||
+ | ====Execution contexts==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc run_loop}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Execution domains==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc default_domain}} | ||
+ | {{dsc inc|cpp/execution/dsc transform_sender}} | ||
+ | {{dsc inc|cpp/execution/dsc transform_env}} | ||
+ | {{dsc inc|cpp/execution/dsc apply_sender}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Forward progress guarantee==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc forward_progress_guarantee}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Environments==== | ||
+ | {{todo|WIP update to current standard in progress}} | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc empty_env}} | ||
+ | {{dsc inc|cpp/execution/dsc get_env}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Queries==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc inc|cpp/execution/dsc forwarding_query}} | ||
+ | {{dsc inc|cpp/execution/dsc get_allocator}} | ||
+ | {{dsc inc|cpp/execution/dsc get_stop_token}} | ||
+ | {{dsc inc|cpp/execution/dsc get_domain}} | ||
+ | {{dsc inc|cpp/execution/dsc get_scheduler}} | ||
+ | {{dsc inc|cpp/execution/dsc get_delegation_scheduler}} | ||
+ | {{dsc inc|cpp/execution/dsc get_completion_scheduler}} | ||
+ | {{dsc inc|cpp/execution/dsc get_forward_progress_guarantee}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Completion signatures==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc completion_signatures}} | ||
+ | {{dsc inc|cpp/execution/dsc get_completion_signatures}} | ||
+ | {{dsc inc|cpp/execution/dsc transform_completion_signatures}} | ||
+ | {{dsc inc|cpp/execution/dsc transform_completion_signatures_of}} | ||
+ | {{dsc inc|cpp/execution/dsc tag_of_t}} | ||
+ | {{dsc inc|cpp/execution/dsc value_types_of_t}} | ||
+ | {{dsc inc|cpp/execution/dsc error_types_of_t}} | ||
+ | {{dsc inc|cpp/execution/dsc sends_stopped}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Coroutine utility==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc as_awaitable}} | ||
+ | {{dsc inc|cpp/execution/dsc with_awaitable_senders}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Core operations=== | ||
+ | ====Operation state==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc connect}} | ||
+ | {{dsc inc|cpp/execution/dsc start}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Completion functions==== | ||
+ | These functions are called by senders to announce the completion of the work to their receivers. | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc set_value}} | ||
+ | {{dsc inc|cpp/execution/dsc set_error}} | ||
+ | {{dsc inc|cpp/execution/dsc set_stopped}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Sender algorithms=== | ||
+ | <!--{{dsc namespace|std::execution}}--> | ||
+ | {{todo|WIP update to current standard in progress}} | ||
====Sender factories==== | ====Sender factories==== | ||
− | A sender factory | + | A sender factory is a function that returns a sender and whose parameters have types for which the {{lconcept|sender}} concept is {{c|false}}. |
− | + | The following are sender factories: | |
− | + | ||
{{dsc begin}} | {{dsc begin}} | ||
Line 44: | Line 161: | ||
{{dsc inc|cpp/execution/dsc just_error}} | {{dsc inc|cpp/execution/dsc just_error}} | ||
{{dsc inc|cpp/execution/dsc just_stopped}} | {{dsc inc|cpp/execution/dsc just_stopped}} | ||
− | {{dsc inc|cpp/execution/dsc | + | {{dsc inc|cpp/execution/dsc read_env}} |
{{dsc inc|cpp/execution/dsc schedule}} | {{dsc inc|cpp/execution/dsc schedule}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ====Pipeable sender adaptors==== | ||
+ | {{dsc begin}} | ||
+ | {{dsc header|execution}} | ||
+ | {{dsc namespace|std::execution}} | ||
+ | {{dsc inc|cpp/execution/dsc sender_adaptor_closure}} | ||
{{dsc end}} | {{dsc end}} | ||
====Sender adaptors==== | ====Sender adaptors==== | ||
− | A sender adaptor | + | A sender adaptor is a function returning a sender whose parameters include at least one whose type satisfies the {{lconcept|sender}} concept, and for which the returned sender is a parent sender of the adaptor function's sender arguments. |
− | + | ||
− | + | ||
+ | The following are sender adaptors: | ||
{{dsc begin}} | {{dsc begin}} | ||
{{dsc header|execution}} | {{dsc header|execution}} | ||
{{dsc namespace|std::execution}} | {{dsc namespace|std::execution}} | ||
− | {{dsc inc|cpp/execution/dsc | + | {{dsc inc|cpp/execution/dsc starts_on}} |
− | {{dsc inc|cpp/execution/dsc | + | {{dsc inc|cpp/execution/dsc continues_on}} |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
{{dsc inc|cpp/execution/dsc on}} | {{dsc inc|cpp/execution/dsc on}} | ||
− | {{dsc inc|cpp/execution/dsc | + | {{dsc inc|cpp/execution/dsc schedule_from}} |
− | + | ||
− | + | ||
{{dsc inc|cpp/execution/dsc then}} | {{dsc inc|cpp/execution/dsc then}} | ||
− | |||
{{dsc inc|cpp/execution/dsc upon_error}} | {{dsc inc|cpp/execution/dsc upon_error}} | ||
{{dsc inc|cpp/execution/dsc upon_stopped}} | {{dsc inc|cpp/execution/dsc upon_stopped}} | ||
+ | {{dsc inc|cpp/execution/dsc let_value}} | ||
+ | {{dsc inc|cpp/execution/dsc let_error}} | ||
+ | {{dsc inc|cpp/execution/dsc let_stopped}} | ||
+ | {{dsc inc|cpp/execution/dsc bulk}} | ||
+ | {{dsc inc|cpp/execution/dsc split}} | ||
{{dsc inc|cpp/execution/dsc when_all}} | {{dsc inc|cpp/execution/dsc when_all}} | ||
+ | {{dsc inc|cpp/execution/dsc when_all_with_variant}} | ||
+ | {{dsc inc|cpp/execution/dsc into_variant}} | ||
+ | {{dsc inc|cpp/execution/dsc stopped_as_optional}} | ||
+ | {{dsc inc|cpp/execution/dsc stopped_as_error}}<!--dropped | ||
+ | {{dsc inc|cpp/execution/dsc ensure_started}} | ||
+ | {{dsc inc|cpp/execution/dsc transfer}}--> | ||
{{dsc end}} | {{dsc end}} | ||
− | ===Sender consumers=== | + | ====Sender consumers==== |
− | A sender consumer is an algorithm that takes one or more senders as parameters and | + | A sender consumer is an algorithm that takes one or more senders as parameters and that does not return a sender. |
{{dsc begin}} | {{dsc begin}} | ||
{{dsc header|execution}} | {{dsc header|execution}} | ||
− | |||
− | |||
− | |||
− | |||
{{dsc namespace|std::this_thread}} | {{dsc namespace|std::this_thread}} | ||
{{dsc inc|cpp/thread/dsc sync_wait}} | {{dsc inc|cpp/thread/dsc sync_wait}} | ||
− | + | {{dsc inc|cpp/thread/dsc sync_wait_with_variant}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | {{dsc inc|cpp/ | + | |
{{dsc end}} | {{dsc end}} | ||
Line 112: | Line 227: | ||
std::jthread worker([&](std::stop_token st) | std::jthread worker([&](std::stop_token st) | ||
{ | { | ||
− | std::stop_callback cb{ st, [&]{ loop.finish(); }<!---->}; | + | std::stop_callback cb{st, [&]{ loop.finish(); }<!---->}; |
loop.run(); | loop.run(); | ||
}); | }); | ||
Line 121: | Line 236: | ||
{{!}} std::execution::then([](std::string msg) | {{!}} std::execution::then([](std::string msg) | ||
{ | { | ||
− | std::puts(msg.c_str()) | + | return std::puts(msg.c_str()); |
− | + | ||
}); | }); | ||
Latest revision as of 19:26, 11 November 2024
The Execution 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.
Contents |
[edit] 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.
- 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 set of key/value pairs 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.
- Scheduler: A lightweight handle to an execution context.
- An execution context is a source of asynchronous execution such as a thread pool or a GPU stream.
- A scheduler is a factory for a sender that completes its receiver from a thread of execution owned by the execution context.
[edit] Library utilities
[edit] Concepts
[edit] Schedulers
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is a scheduler (concept) |
[edit] 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 a sender that can connect with a specific receiver type (concept) |
[edit] Receivers
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is a receiver (concept) |
(C++26) |
specifies that a type is a receiver for given completion signatures (concept) |
[edit] Operation states
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
specifies that a type is an operation state (concept) |
[edit] Utility components
[edit] 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) |
[edit] 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) |
transforms into a new queryable object 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) |
[edit] 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) |
[edit] Environments
This section is incomplete Reason: WIP update to current standard in progress |
Defined in header
<execution> | |
Defined in namespace
std::execution | |
(C++26) |
default environment type in which no query object can ask for its value (class) |
(C++26) |
returns the associated queryable object for its given argument (customization point object) |
[edit] 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) |
(C++26) |
asks a queryable object for its associated scheduler (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) |
[edit] 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) | |
transforms one set of completion signatures into another (alias template) | |
transforms completion signatures of a sender (alias template) | |
(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) |
[edit] 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) |
[edit] Core operations
[edit] 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) |
[edit] 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) |
[edit] Sender algorithms
This section is incomplete Reason: WIP update to current standard in progress |
[edit] 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) |
[edit] 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) |
[edit] 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) |
TODO (customization point object) |
(C++26) |
TODO (customization point object) |
(C++26) |
start the provided sender on an execution agent belonging to the execution resource associated with the provided scheduler (customization point object) |
(C++26) |
TODO (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) |
(C++26) |
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) |
if the provided sender is a multi-shot sender, returns that sender, otherwise, returns a multi-shot sender which sends values equivalent to the values sent by the provided sender (customization point object) |
(C++26) |
completes once all of the input senders have completed (customization point object) |
TODO (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) |
[edit] 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) |
[edit] 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
[edit] 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) |