2023/08/12(土)C++20のコルーチンでタスクシステム(?)作ってみた

はてブ数 2023/08/11 17:47 プログラミング::C++つーさ

夏休みの自由研究じゃないけど、ふと思い立ってC++20のコルーチンでタスクシステムっぽいものを書いたらどうなるかやってみた。タスクシステムっていうかつまるところファイバーコンテナだけど。

それなりうまくいった

👇最初のバージョン。

なんとなく動いてはいる。動いてはいるが、C++20のコルーチンはスタックレスなので、コルーチンの中でさらに他のコルーチンを作って待つには、待っている間親側もループで子供のresume()を呼んで、おわるの待たないといけない。ちょっとダサい。いわゆる他の言語の await みたいに、できれば、サブタスクを呼ぶのに co_await Task(); な感じで書けるようにしてみたい。

👇実行スタックを作ろう。

で、コネコネして、こうかな。

これなら、 co_task<int> CreateSubTask(std::string, int); から作られるコルーチンのco_returnの結果を、auto sub_task_result = co_await CreateSubTask(label, 3); みたいな感じで受け取れるので、ちょっといい感じ。😼👍

2023.08.14追記: ついでに、サブスレッド待てるように co_await std::future<...> もできるようにしてみた。

ゲームで使うんならメインスレッドで回すゲームループと同期してコルーチンを動かせるのでステートマシン、シーン遷移定義とかのフレームまたいだフロー制御とかを、ちょっと楽に書けるようになるかしら。ただ、ファイバーはファイバーだから、サブコルーチン呼び出したら、それがおわるまで戻ってこないので、シーン内のゲームオブジェクトのツリー管理の目的にはあまり向かない。その用途では co_await じゃなくて、素直に各階層で子の配列を持った方がいいね。

あとは、今の実装は、コルーチンの戻り値受け渡しにに std::promise/std::futureとか使ってるから、オーバーヘッドままありそう。シングルスレッドならこの手の同期オブジェクトは要らないから std::variant<std::monostate, result_type, std::exception_ptr> みたいなので、 promise/future を実装する方がいいはず、たぶん。