N2671 - 非同期 Future Value
そういえば大分前に翻訳して貼ってなかったので。
概念的には、マルチスレッドデザインパターンの Future パターンと全く同じで、値の設定は promise クラスの set_value()、値の取得は unique_future か shared_future の get() から行います。
promise の set_exception() で例外を設定することも可能で、例外をセットすると、unique_future, shared_future の get() で例外が発生します。
unique_future と shared_future の違いは、get() するときに設定されたデータを move するか参照を返して貰うかという違いだけです。内部のデータを move するので、unique_future の2回目以降の get() 呼び出しは unspecified です。
多分使い方はこんな感じ。
struct task { private: std::promise<int> p_; public: task() { } task(task&& t) : p_(std::move(t.p_)) { } task(const task&) = delete; void operator()() { try { p_.set_value(do_something()); } catch (...) { p_.set_exception(std::current_exception()); } } // ここに裏スレッドで行いたい処理を書いて、結果を返す int do_something(); std::unique_future<int> get_future() { return p_.get_future(); } };
// 裏スレッドで task を実行する関数 std::unique_future<int> do_task() { task t; std::unique_future<int> res(t.get_future()); std::thread(std::move(t)); return res; }
// 裏スレッドで処理を行う std::unique_future<int> future = do_task(); // 何か別の処理をする ... // 裏スレッドの結果が本当に必要になったので取得する // もし裏スレッドの処理が終わってない場合は、その処理が終わるのを待つ try { int result = future.get(); std::cout << result << std::endl; } catch (...) { std::cout << "error" << std::endl; }
ちなみに packaged_task は削除されたとか書いてるけど、この後の N2709 で復活してます。
↑の処理も packaged_task を使えばもっと簡単に書けるようになるので、後日書きます。