OpenSiv3Dで非同期処理をする
久し振りに C++
を触り、OpenSiv3D
で単純な非同期の処理をした際に色々知らなかったことが多かったので忘れないうちに備忘録として書いておきます。バージョンは OpenSiv3D 0.4.1です。タイトルにデカデカと入れといてなんですが、あまりOpenSiv3D要素はありません。
最小コード
時間がかかる関数を heavyFunction()
を非同期で実行し、計算中は "計算中..."
と表示し計算が完了したら結果を表示するコードは以下のようになります。
# include <Siv3D.hpp> // v0.4.1
# include <future>
double heavyFunction() {
// 何か重い処理
System::Sleep(3s);
return 1.0;
}
// 非同期関数の結果をOptional型で返す関数
template<class T>
Optional<T> resultOr(std::shared_future<T> task) {
if (task.valid()) {
auto status = task.wait_for(0s);
if (status == std::future_status::ready) {
return task.get();
}
}
return none;
}
void Main() {
const Font font(24);
std::shared_future<double> task = std::async(std::launch::async, heavyFunction).share();
while(System::Update()) {
font(resultOr<double>(task).map(Format).value_or(U"計算中...")).draw();
}
}
std::shared_future
は shared
な std::future
みたいな感じです。(これ以上説明できません)
関数 Optional<T> resultOr(std::shared_future<T> task)
は Siv3Dの Optional型を返り値とし、 std::shared_future
の処理が完了していたら std::shared_future::get()
し、そうでなければ、 none
を返す関数です。
task.wait_for(0s)
の部分はメインスレッドをブロックせずにタスクの状態を取得する為 0s
ウェイトしている様です。
C++
無限に知らないことが出てくるから怖い。正直これがベストプラクティスだとは思っていないので マサカリお待ちしております。
個人的には OpenSiv3Dに JavaScript/TypeScript
の Promise
並に扱いやすい非同期処理まわりのラッパがあると嬉しいかも?
最近は3Dの機能も着々と実装され増々便利になっています!
OpenSiv3Dはいいぞ!
参考
AziOGroup Lab,: std::asyncで開始したスレッドの終了確認 [C++]
std::future as a parameter to a function C++ - Stack Overflow