💨

C++26 の std::execution の概念まとめ [WIP]

2024/07/30に公開

概要

P2300 std::execution がついに C++26 入りしたとのことで、自分のためにもどういった設計になっているのかを用語を整理しながら見ていこうと思います。

CPO の種別について

std::execution には多くの CPO (customization point object) が登場しますが、どうやらそれらには種別があるようです(規格書にも下記と同様の表が載っています)

種別 説明 具体例
core std::execution の機能のコアとなる start, connect
completion functions sender が完了を通知する際に呼ばれる関数 set_value, set_error, set_stopped
senders sender アルゴリズムのカスタマイズを可能にする schedule, then, sync_wait
queries オブジェクトへの性質の問い合わせを可能にする get_allocator, get_scheduler, get_completion_scheduler

用語の定義など

query object, queryable object

queryable objectquery object と呼ばれる CPO を Key とする Key/Value ペアの集合であり、query objectqueryable object を渡すことで各 query object に対応する queryable object の性質を問い合わせることができます。

execution resource

execution resource は並列で処理を行う可能性のある execution agent を管理するプログラムの実体であり、asynchronous operation を実行します。

asynchronous operation

asynchronous operation は結果のデータと次の三つの完了状態(disposition)のうちいずれかを以て完了するような独立した処理です。

  • 成功 (successful completion a.k.a. value completion)
    • 任意個の結果のデータを持つことができる
  • 失敗 (failure completion a.k.a. error completion)
    • 一つの結果のデータを持つ
  • キャンセル (cancellation completion a.k.a. stopped completion)
    • 結果のデータを持たない

また、開始されたのと異なる execution resource において完了したり、自身を parent operation として、自身が完了するより前に完了する child operation を開始する可能性があります。

operation state, environment, receiver

asynchronous operation には operation state と呼ばれる関連した状態があり、environment という呼び出し元の実行時の性質を表す queryable objectreceiver を所有します。
asynchronous operation には関連した receiver があり、これは完了状態に応じた三つのハンドラを集約したものです。
receiver に関連する environmentoperation state に関連する environment と等しいです。

completion function, completion signature

asynchronous operation の三つの完了状態のそれぞれに対し completion function と呼ばれる CPO が存在し、receiver と結果のデータを引数に取り receiver のハンドラを呼び出します。
正当(valid)な completion function の呼び出しは completion operation と呼ばれます。
completion signaturecompletion operation を表す関数の型です。

sender, attribute

sender は一つ以上の asynchronous operation のためのファクトリであり、 senderreceiver とを std::execution::connect によって connect することで asynchronous operation が作成されます。
sender には関連する queryable object があり、attribute と呼ばれます。

scheduler

schedulerexection resource の抽象化であり、処理のスケジューリングに対する汎用なインターフェースを提供します。
schedulersender に対するファクトリであり、 scheduler sch に対する std::execution::schedule(sch) の呼び出しにより sender が作成されます。

completion scheduler

asynchronous operation には一つ以上の関連した completion scheduler があり、それらは completion operation を実行する scheduler です。

sender algorithm

sender アルゴリズムは sender を受け渡しする関数群であり、三つのカテゴリに分類されます。

  • sender factory
    • sender を引数に取り sender を返す
  • sender adaptor
    • sender と(あれば)追加の引数を取り sender を返す
  • sender consumer
    • sender を引数に取り非 sender を返す

以下書きかけ

詳細

query object の一覧

std::forwarding_query

std::forwarding_queryquery object 自体に問い合わせを行う query object です。その仕様は「query object q に対して std::forwarding_query(q)false を返す場合、queryable object envexposition-only entity FWD-ENV(...) について FWD-ENV(env).query(q, args...)ill-formed になる」というものですが、つまり特定の箇所において env を引き渡す際に引き渡し以降の問い合わせを禁止するかどうかという性質のようです。

struct my_query_object_t {
  constexpr bool query(std::forwarding_query_t) { return false; }

  template <class Env>
  decltype(auto) operator()(const Env& env) const noexcept {
    return env.query(my_query_object_t{});
  }
};

inline constexpr my_query_object_t my_query_object{};

struct my_receiver {
  using receiver_concept = std::execution::receiver_t;
  void set_value(auto&&...) const noexcept {}
  void set_error(auto&&) const noexcept {}
  void set_stopped() const noexcept {}
  struct env {
    std::allocator<void> query(std::get_allocator_t) const noexcept { return {}; }
    int query(my_query_object_t) const noexcept { return 42; }
  };
  env get_env() const noexcept { return {}; }
};

static_assert(    std::forwarding_query(std::get_allocator));
static_assert(not std::forwarding_query(   my_query_object));

my_receiver recv;
auto env = std::execution::get_env(recv);

auto alloc = std::get_allocator(env);  // well-formed
auto my_value = my_query_object(env);  // well-formed

auto env2 = FWD-ENV(env);  // FWD-ENV を通す

auto alloc2 = std::get_allocator(env2);  // well-formed
auto my_value2 = my_query_object(env2);  // !!! ill-formed !!!

std::get_allocator

std::get_allocatorqueryable object に関連する allocator を問い合わせます。例えば asynchronous operation を表すオブジェクトが特定の allocator を使用して構築されている場合それを使用して破棄する必要があり、そういった場面で使われるのだと思われます。

std::get_stop_token

std::get_stop_tokenqueryable object に関連する stop token を問い合わせます。

std::execution::get_env

std::execution​::​get_env は、 sender に対しては attribute を、receiver に対しては environment を問い合わせます。
元々は前者の問い合わせのために get_attr なる query object が存在していましたが、get_env に統合されたようです。

std::execution::get_domain

domain と呼ばれる、sender が完了する scheduler に関連するタグ型を問い合わせます。

GitHubで編集を提案

Discussion