Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/execution"

From cppreference.com
< cpp
m (some in-house formatting.)
Line 2: Line 2:
 
{{cpp/experimental/execution/navbar}}
 
{{cpp/experimental/execution/navbar}}
  
{{fmbox|class=noprint|style=font-size: 0.8em|text='''Note''' This is a planned '''extention''' to the <execution> {{mark c++17}} header;}}
+
{{fmbox|class=noprint|style=font-size: 0.8em|text='''Note''' This is a planned '''extension''' to the <execution> {{mark c++17}} header;}}
  
 
{{fmbox|class=noprint|style=font-size: 0.8em|text='''Draft''' The functionality described on this page is a draft, based on the latest revision of P2300, targeting {{mark c++26}};}}
 
{{fmbox|class=noprint|style=font-size: 0.8em|text='''Draft''' The functionality described on this page is a draft, based on the latest revision of P2300, targeting {{mark c++26}};}}
  
  
The Execution library suggests a framework for managing asynchronous execution on generic execution resources, targeting the standard C++ library.
+
The Execution library provides a framework for managing asynchronous execution on generic execution resources, targeting the standard C++ library.
  
 
The library aims to provide vocabulary types for async operations and to allow the construction of tasks execution graphs in a simple, composable way.
 
The library aims to provide vocabulary types for async operations and to allow the construction of tasks execution graphs in a simple, composable way.
  
 
===Library-wide definitions===
 
===Library-wide definitions===
 
 
* '''Sender''' - Contains data and/or work to be sent for execution.
 
* '''Sender''' - Contains data and/or work to be sent for execution.
 
:* Senders can be chained to build execution pipes (translated into a task graph).
 
:* Senders can be chained to build execution pipes (translated into a task graph).
Line 25: Line 24:
  
 
====Sender Factories====
 
====Sender Factories====
 
 
A sender factory takes a non-sender (function/data) and returns a sender.
 
A sender factory takes a non-sender (function/data) and returns a sender.
  
Line 43: Line 41:
  
 
====Sender Adaptors====
 
====Sender Adaptors====
 
 
A sender adaptor takes a sender and returns a sender.
 
A sender adaptor takes a sender and returns a sender.
  
 
=====Adaptors for Either a Single-Shot or Multi-Shot Sender=====
 
=====Adaptors for Either a Single-Shot or Multi-Shot Sender=====
 
 
{{dsc begin}}
 
{{dsc begin}}
 
{{dsc header|execution}}
 
{{dsc header|execution}}
Line 66: Line 62:
  
 
=====Adaptors which creates a Multi-Shot Senders=====
 
=====Adaptors which creates a Multi-Shot Senders=====
 
 
{{dsc begin}}
 
{{dsc begin}}
 
{{dsc header|execution}}
 
{{dsc header|execution}}
Line 74: Line 69:
 
{{dsc inc|cpp/execution/dsc when_all}}
 
{{dsc inc|cpp/execution/dsc when_all}}
 
{{dsc end}}
 
{{dsc end}}
 
  
 
===Example===
 
===Example===
 
{{example
 
{{example
|Note: the example is using [https://github.com/NVIDIA/stdexec stdexec] (available on [https://godbolt.org/z/1sfTY8zfr godbolt]), which is an experimental reference implementation for "std::execution".  
+
|Uses [https://github.com/NVIDIA/stdexec stdexec] (available on [https://godbolt.org/z/1sfTY8zfr godbolt]), which is an experimental reference implementation for {{lc|std::execution}}.
 
|code=
 
|code=
#include <thread>
 
 
#include <iostream>
 
#include <iostream>
 
#include <stdexec/execution.hpp>
 
#include <stdexec/execution.hpp>
 +
#include <thread>
  
 
using namespace std::literals;
 
using namespace std::literals;
Line 88: Line 82:
 
std::thread worker([]{ loop.run(); });
 
std::thread worker([]{ loop.run(); });
  
 
+
int main()
int main()  
+
 
{
 
{
  auto hello = stdexec::just("hello world"s);
+
    auto hello = stdexec::just("hello world"s);
  auto work = hello {{!}} stdexec::then( [](auto msg) {
+
    auto work = hello {{!}} stdexec::then([](auto msg)
      std::cout << msg << '\n';
+
    {
      return 0;
+
        std::cout << msg << '\n';
  });
+
        return 0;
 +
    });
  
  auto [result] = stdexec::sync_wait(stdexec::on(loop.get_scheduler(), std::move(work))).value();
+
    const auto [result] =
  loop.finish();
+
        stdexec::sync_wait(stdexec::on(loop.get_scheduler(), std::move(work))).value();
  worker.join();
+
    loop.finish();
  return result;
+
    worker.join();
 +
    return result;
 
}
 
}
 +
|output=
 +
hello world
 
}}
 
}}

Revision as of 18:16, 24 January 2024


The Execution library provides a framework for managing asynchronous execution on generic execution resources, targeting the standard C++ library.

The library aims to provide vocabulary types for async operations and to allow the construction of tasks execution graphs in a simple, composable way.

Contents

Library-wide definitions

  • Sender - Contains data and/or work to be sent for execution.
  • Senders can be chained to build execution pipes (translated into a task graph).
  • Different types of senders can be produced by senders factories/adaptors.
  • Receiver/Sender Consumer - Closure of execution pipe, consume sender(s) and returns an Operation State.
  • Receiver contains environment, which holds data on the execution context
  • By default (if not provided) the environment is the default env.
  • Operation State - Object which holds: data + work + execution context. Execution by calling “state”
  • Scheduler - Execution context on which operation can run (CPU, thread pool, GPU threads, Event loop, etc.)

Senders

Sender Factories

A sender factory takes a non-sender (function/data) and returns a sender.

A sender with no completion schedulers is an “open-ended” operation, that can be used in the pipe. All the following senders are created without a completion scheduler.

Template:cpp/execution/dsc read
Defined in header <execution>
Defined in namespace std::execution
prepares a task graph for execution on a given scheduler
(customization point object)[edit]
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)[edit]
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)[edit]
creates a sender that completes immediately by calling its receiver's set_stopped
(customization point object)[edit]


Sender Adaptors

A sender adaptor takes a sender and returns a sender.

Adaptors for Either a Single-Shot or Multi-Shot Sender
Defined in header <execution>
Defined in namespace std::execution
Returns a sender describes transition from the execution context of the input sender to the execution context of the target scheduler
(function template) [edit]
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)[edit]
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)[edit]
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)[edit]
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)[edit]
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)[edit]
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)[edit]
start the provided sender on an execution agent belonging to the execution resource associated with the provided scheduler
(customization point object)[edit]
returns a sender which sends a variant of tuples of all the possible sets of types sent by the input sender
(customization point object)[edit]
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)[edit]
returns a sender that maps the stopped channel to an error
(customization point object)[edit]
Eagerly starts a sender, returning a sender that will deliver the results to a receiver to which it is connected and started, if any. When the result sender is not connected to a receiver, or if the resulting operation state is not started, the results are ignored. If such a sender is destroyed before the underlying operation completes, the operation continues running detached.
(function template) [edit]
Adaptors which creates a Multi-Shot Senders
Defined in header <execution>
Defined in namespace std::execution
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)[edit]
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)[edit]
completes once all of the input senders have completed
(customization point object)[edit]

Example

Uses stdexec (available on godbolt), which is an experimental reference implementation for std::execution.

#include <iostream>
#include <stdexec/execution.hpp>
#include <thread>
 
using namespace std::literals;
stdexec::run_loop loop;
std::thread worker([]{ loop.run(); });
 
int main()
{
    auto hello = stdexec::just("hello world"s);
    auto work = hello | stdexec::then([](auto msg)
    {
        std::cout << msg << '\n';
        return 0;
    });
 
    const auto [result] =
        stdexec::sync_wait(stdexec::on(loop.get_scheduler(), std::move(work))).value();
    loop.finish();
    worker.join();
    return result;
}

Output:

hello world