namespace std::execution {
class inline_scheduler {
class inline-sender; // exposition only
template <receiver R>
class inline-state; // exposition only
public:
using scheduler_concept = scheduler_tag;
constexpr inline-sender schedule() noexcept { return {}; }
constexpr bool operator==(const inline_scheduler&) const noexcept = default;
};
}
概要
inline_schedulerは、インラインでタスクを実行するSchedulerである。
schedule操作により得られるSenderとReceiverを接続(connect)したOperationStateは、開始(start)したスレッド上で即座に値完了する。
戻り値型task<T, E>を持つタスクコルーチンのScheduler型として利用すると、コルーチン内でco_await式から再開(resume)時のスケジューリング操作を回避できる(動作詳細はawait_transformを参照)。
クラス仕様
inline_scheduler型の全オブジェクトは等しい。inline_scheduler型の部分式sch、クエリオブジェクトq、部分式のパックargsとしたとき、式sch.query(q, args...)はinline-attrs<set_value_t>.query(q, args...)と等価な式となる。
説明専用のクラスinline-senderをsenderを満たす型とする。completion_signatures_of_t<inline-sender>は、completion_signatures<set_value_t()>となる。
説明用のsndrをinline-sender型の式とする。CSをcompletion_signatures<set_value_t()>としたとき、rcvrをreceiver-of<decltype((rcvr)), CS>がtrueとなる式とする。式connect(sndr, rcvr)の型はinline-state<remove_cvref_t<decltype((rcvr))>>であり、式((void)sndr, auto(rcvr))が潜在的に例外送出(potentially-throwing)するときに限って潜在的に例外送出する。
説明用のoをinline-state<Rcvr>型の非const左辺値とし、REC(o)をoを返す接続(connect)呼び出しへ渡した式rcvrで初期化されたRcvr型の非const左辺値参照とする。
説明専用クラステンプレートinline-attrs
template<class Tag>
struct inline-attrs {
see below
};
envとしたとき、inline-attrs<Tag>{}.query(get_completion_scheduler<Tag>, env)はget_scheduler(env)と等価な式となる。
部分式envとしたとき、inline-attrs<Tag>{}.query(get_completion_domain<Tag>, env)はget_domain(env)と等価な式となる。
メンバ関数
| 名前 | 説明 | 対応バージョン |
|---|---|---|
(constructor) |
コンストラクタ | C++26 |
(destructor) |
デストラクタ | C++26 |
schedule |
スケジュールSenderを返す | C++26 |
メンバ型
| 名前 | 説明 | 対応バージョン |
|---|---|---|
scheduler_concept |
scheduler_tag |
C++26 |
例
#include <execution>
#include <thread>
#include <print>
namespace ex = std::execution;
// ex::task用のカスタム環境
struct TaskEnv {
using start_scheduler_type = ex::inline_scheduler;
};
ex::task<void> f(ex::scheduler auto sch)
{
std::println("step1 main#{}", std::this_thread::get_id());
// スケジューラを変更してサブタスクを実行
co_await (ex::schedule(sch) | ex::then([]{
std::println("step2 worker#{}", std::this_thread::get_id());
}));
// デフォルト(task_scheduler)タスクコルーチンのco_await式では、
// Scheduler Affinity動作により元のスケジューラ上で処理が継続する。
std::println("step3 main#{}", std::this_thread::get_id());
}
ex::task<void, TaskEnv> g(ex::scheduler auto sch)
{
std::println("step1 main#{}", std::this_thread::get_id());
// スケジューラを変更してサブタスクを実行
co_await (ex::schedule(sch) | ex::then([]{
std::println("step2 worker#{}", std::this_thread::get_id());
}));
// inline_schedulerを持つタスクコルーチンのco_await式では、
// コルーチンの再開(resume)時に再スケジューリングが行われない。
// このためco_await式内で変更したスケジューラが引き継がれる。
std::println("step3 worker#{}", std::this_thread::get_id());
}
int main()
{
// ワーカースレッドを開始
ex::run_loop loop;
std::jthread worker{[&]{
loop.run();
}};
auto sch = loop.get_scheduler();
std::println("task_scheduler(default)");
std::this_thread::sync_wait( f(sch) );
std::println("inline_scheduler");
std::this_thread::sync_wait( g(sch) );
loop.finish();
}
出力例
task_scheduler(default)
step1 main#124468393588544
step2 worker#124468391311040
step3 main#124468393588544
inline_scheduler
step1 main#124468393588544
step2 worker#124468391311040
step3 worker#124468391311040
バージョン
言語
- C++26
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??