执行库

来自cppreference.com


执行库提供了一个用于管理通用执行资源上的异步执行的框架,针对标准 C++ 库设计。

这个库的目标是提供针对异步操作的基本术语类型,并允许以一种简便和可组合的方式构建任务执行图。

库范围的定义

  • 发送器:对要发送去执行的工作的描述。产生一个操作状态(见下文)。
  • 发送器将它们的结果异步“发送”给称为“接收器”(见下文)的监听者。
  • 可以用通用算法把发送器组合成任务图
  • 发送器工厂/适配器是捕捉了满足 sender 概念的对象中的常见异步模式的通用算法。
  • 接收器:泛化的回调,它消耗或“接受”由发送器产生的异步结果。
  • 接收器包含三个不同“通道”,发送器可以通过它们传播成功、失败和取消的结果,分别称为“值”、“错误”和“停止”通道。
  • 接收器提供一个可扩展的执行环境:可以由消耗方用来参数化异步操作的一组键/值对。
  • 操作状态:包含异步操作所需状态的对象。
  • 当发送器和接收器被传递给 std::execution::connect 时,它们就被连接起来。
  • 将发送器和接收器连接起来的结果就是一个操作状态。
  • 当在操作状态上调用“start”后,其工作才会加入队列执行。
  • 一旦启动,则操作状态的生存期在异步操作完成前都不会结束,且其地址必须稳定。
  • 调度器:对执行上下文的轻量级句柄。
  • 执行上下文是诸如线程池或 GPU 流这样的异步执行源。
  • 调度器是一个工厂或发送器,它在执行上下文所拥有的某个执行线程中完成其接收器。

库工具

发送器

发送器工厂

发送器工厂是返回发送器的函数,且其形参具有使得 senderfalse 的类型。

以下为发送器工厂:

在标头 <experimental/execution> 定义
在命名空间 std::execution 定义
接受一组可变数量的实参并返回一个发送器,当它被连接并启动时,将通过把各实参传递给接收器的值完成函数而同步地完成。
(函数模板)
接受单个实参并返回一个发送器,当它被连接并启动时,将通过把实参传递给接收器的错误完成函数而同步地完成。
(函数模板)
可以无实参调用的函数,它返回的发送器当被连接并启动时,将通过调用接收器的停止完成函数而同步地完成。
(函数)
可以一个查询对象(例如 std::get_stop_token)调用的函数,它所返回的发送器当被连接到接收器并启动时,将以接收器的环境来同步地调用查询对象,并将结果传递给接收器的值完成函数。
(函数模板)
接受一个调度器的函数,其所返回的发送器当被连接并启动时,将尝试把一次没有结果数据的值完成操作加入属于此调度器的关联执行资源的某个执行代理的队列。该操作也可以以错误(例如任务入队的尝试失败)或停止(例如在任务出队前在执行资源上请求了停止)完成。
(函数模板)

发送器适配器

发送器适配器是返回发送器的函数,且它包含至少一个形参的类型满足 sender 概念,且所返回的发送器是此适配器函数的发送器实参的父发送器。

以下为发送器适配器:

在标头 <experimental/execution> 定义
在命名空间 std::execution 定义
创建一个多发发送器,它以所提供的形状中的每个索引和输入发送器所发送的值的来调用函数。该发送器在所有调用完成后,或发送错误时完成。
(函数模板)
急切地启动一个发送器,返回一个发送器,它将把结果递交给它所连接并启动的接收器(如果有)。如果结果发送器并未连接到接收器,或如果结果的操作状态并未启动,那么忽略其结果。如果这种发送器在底层操作完成前被销毁,则操作继续脱离运行。
(函数模板)
返回一个发送器,发送输入发送器发送的所有可能类型集合的元组的变体。
(函数模板)
返回表示一个串联到输入发送器的节点的发送器,它以输入发送器的错误(若发生)调用所提供的函数。
(函数模板)
返回表示一个串联到输入发送器的节点的发送器,启动时,以输入发送器所发送的值为实参调用所提供的函数。
(函数模板)
返回表示一个串联到输入发送器上的节点的发送器,当发送了“停止”信号时,以输入发送器的停止令牌调用所提供的函数。
(函数模板)
在某个属于于所提供调度器关联的执行资源的执行代理上启动所提供的发送器。
(函数模板)
如果所提供的发送器是多发的,则返回该发送器。否则返回发送与所提供发送器所发送的值等价的值的多发发送器。
(函数模板)
返回将停止通道映射为一个错误的发送器。
(函数模板)
返回将值通道映射为 std::optional<std::decay_t<T>> 并将停止通道映射为 std::nullopt 的发送器。
(函数模板)
以一个节点串联输入发送器的任务图,该节点表示以输入发送器所发送的各值为实参调用所提供的函数。
(函数模板)
返回描述从输入发送器的执行上下文迁移到目标调度器的执行上下文的发送器
(函数模板)
以一个节点串联输入发送器的任务图,该节点表示当发送错误时以输入发送器所发送的错误调用所提供的函数。
(函数模板)
以一个节点串联输入发送器的任务图,该节点表示当被发送“停止”信号时以输入发送器的停止行为调用所提供的函数。
(函数模板)
当所有输入发送器都已完成时完成。其值为各个输入发送器所发送的值,按传递给 when_all 的实参顺序。在最后完成的输入发送器所在执行资源上内联完成。
(函数模板)

发送器消耗器

发送器消耗器是一种算法,它接受一个或多个发送器为参数且并不返回发送器。

以下为发送器消耗器:

在标头 <experimental/execution> 定义
在命名空间 std::execution 定义
当所提供发送器完成时完成,或当发送器发送错误时调用 std::terminate
(函数模板)
管理当前线程的函数
在标头 <experimental/execution> 定义
在命名空间 std::this_thread 定义
(C++26)
阻塞当前线程直至所传递的发送器完成,并返回该发送器所完成的值(如果有)
(函数模板)

急切执行

允许“发射后不管”的急切任务提交可调用体给调度器。

在标头 <experimental/execution> 定义
在命名空间 std::execution 定义
提交所提供的函数在所提供的调度器上执行。
(函数模板)

示例

此示例的一个版本在 godbolt.org,它使用的是 stdexec,一个 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)
        {
            std::puts(msg.c_str());
            return 0;
        });
 
    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;
}

输出:

hello world

参阅

(C++11)
异步运行一个函数(有可能在新线程中执行),并返回将保有它的结果的 std::future
(函数模板)