According to the general idea of std::execution
In my previous blog post I dedicated myself to adaptive asynchronous algorithms.
Advertisement
It’s not easy, offer P2300R10 introduce. Firstly it is powerful and secondly it is very long. Therefore, I focus on a few aspects.
Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages C++, Python, and Haskell, but also frequently speaks at expert conferences. On his blog Modern C++ he discusses his passion C++ in depth.
C++ model preferences
Several priorities apply to the proposal. Must have C++ model for asynchronous code
- Be composable and generic, allowing users to write code that can be used with many different types of execution resources.
- Summarize common asynchronous patterns into customizable and reusable algorithms so that users don’t have to invent everything themselves.
- Making it easier to get right by construction.
- Support a diversity of execution resources and execution agents, as not all execution agents are the same; Some are less powerful than others, but no less important.
- Allow everything to be optimized by an execution resource, including transfer to other execution resources, but do not require execution resources to optimize everything –
Take into account all sensible use cases, domains and platforms. - Make sure errors are passed through but error handling doesn’t become a burden.
- Support termination which is not an error.
- Have clear and precise answers about where things are done.
- Be able to manage and terminate object lifetimes asynchronously.
The terms execution resource, execution agent and scheduler are important to understand. std::execution
Necessary. Here are the first simplified definitions.
One execution resource A program is a resource unit that manages a set of execution agents. Examples of execution resources include active threads, thread pools, or additional hardware accelerators.
every function call is in one execution agent execute.
A scheduler Execution is an abstraction of a resource with a unified, common interface for scheduling work on that resource. That’s a transmitter factory.
Hello World
From here is the “Hello World” program std::execution
This time this program can happen… compiler explorer Play on, and my analysis will go deeper.
// HelloWorldExecution.cpp
#include
#include
#include
int main() {
exec::static_thread_pool pool(8);
auto sch = pool.get_scheduler();
auto begin = stdexec::schedule(sch);
auto hi = stdexec::then(begin, () {
std::cout << "Hello world! Have an int.\n";
return 13;
});
auto add_42 = stdexec::then(hi, ()(int arg) { return arg + 42; });
auto (i) = stdexec::sync_wait(add_42).value();
std::cout << "i = " << i << '\n';
}
First, here is the output of the program:
The program starts by including the required headers:exec/static_thread_pool.hpp
>To create thread pool andstdexec/execution.hpp
>For performance-related utilities.
In main
the function will continue static_thread_pool pool
Made of eight threads.
member work get_scheduler
The thread pool is called to provide a lightweight handle to the execution resource scheduler. sch
Which is used to schedule dispatchers in the thread pool. In this case, the execution resource is a thread pool, but it can also be the main thread, the GPU, or a task framework.
The program then creates a series of dispatchers that are executed by execution agents.
first station begin
will work with the function stdexec::schedule
Created a dispatcher on the specified scheduler sch
Plans. stdexec::schedule
There is a so-called transmitter factory. There are other transmitter factories as well. I am using the namespaces of the upcoming standard:
next station hi
Uses transmitter adapter stdexec::then
which is transmitter begin
And used lambda function. This lambda function returns “Hello world! Have an int
.” on the console and returns an integer value 13
Back. third station add_42
The transmitter also comes with an adapter stdexec::then
created. sequel takes over hi
function and another lambda that has an integer argument arg
Receives and adds result 42
Return. Dispatchers run asynchronously and are generally composable.
std::execution
Additional transmitter adapters provide:
execution::continues_on
execution::then
execution::upon_*
execution::let_*
execution::starts_on
execution::into_variant
execution::stopped_as_optional
execution::stopped_as_error
execution::bulk
execution::split
execution::when_all
Unlike the sender, the sender-consumer runs synchronously. stdexec::sync_wait-
Waiting for call to complete add_42-
transmitter. value
The method is used for the result of sync_wait
Called by the sender to get the value generated, which is passed to the variable i
Unpacked.
this_thread::sync_wait
The only sender in the execution framework is the consumer.
What will happen next?
In my next article I will analyze a more sophisticated algorithm.
(rme)