C++11のドラフト段階では、std::futureにis_ready()というメンバ関数がありました。これは、非同期実行している関数の結果が設定され、値を取り出す準備ができたかどうかを判定する機能です。
C++11が正式に制定された段階では、インタフェースの複雑さ回避のため、is_ready()メンバ関数が削除されてしまいましたが、ここでその機能が必要なケースを挙げてみようと思います。
ここでは、ゲームループのような定期実行される処理の中で、別スレッドで計算を走らせるのにfutureを使用しています。
future::get()は値の準備ができるまでブロッキングしてしまうので、短い時間で定期実行される処理の中では呼びたくありません。そんなときに、futureの状態を問い合わせる関数があると便利です。
以下は、is_ready()のないstd::futureの代わりに、Boost.Threadのfutureを使用しています。
#define BOOST_THREAD_VERSION 3 #include <iostream> #include <boost/bind.hpp> #include <boost/ref.hpp> #include <boost/asio.hpp> #include <boost/asio/steady_timer.hpp> #include <boost/thread.hpp> #include <boost/thread/future.hpp> #include <boost/optional.hpp> namespace asio = boost::asio; namespace chrono = boost::chrono; class Game { bool calc_start_; boost::optional<int> result_; boost::future<int> async_calc_; public: Game() : calc_start_(false) {} void update() { async_calc(); } void draw() { } private: // 非同期に計算を行う void async_calc() { // 3. 計算完了していたらそれ以降は何もしない if (result_) return; if (!calc_start_) { calc_start_ = true; // 1. 別スレッドで計算を開始する async_calc_ = boost::async(boost::launch::async, boost::bind(&Game::calc, this)); } else { // 2. 計算完了したら結果を取り出す if (async_calc_.is_ready()) { result_ = async_calc_.get(); std::cout << result_.get() << std::endl; } } } int calc() const { int sum = 0; for (int i = 0; i < 10; ++i) { sum += i + 1; } return sum; } }; const chrono::milliseconds timer_duration(static_cast<int>(1.0 / 60.0 * 1000)); void on_timer(Game& game, asio::steady_timer& timer) { game.update(); game.draw(); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); } int main() { Game game; asio::io_service io_service; asio::steady_timer timer(io_service); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); io_service.run(); }
55
標準の範囲内でfutureの状態を問い合わせたい場合は、std::future::wait_for()メンバ関数を使用できます。
wait_for()は戻り値として、futureの状態となる列挙値を返し、それにreadyも含まれていることから同じことができます。wait_for()は通常f.wait_for(seconds(3))のようにタイムアウト時間を指定して使いますが、f.wait_for(seconds(0))のようにして現在時間以下を指定することで、ブロッキングすることなくfutureの状態を取り出せます。
参照:
std::future::is_readyが無くなった理由 - melpon日記
std::future::wait_for() - cpprefjp
std::future::wait_until() - cpprefjp