https://yohhoy.hatenadiary.jp/entry/20120131/p1

C++11標準ライブラリで新しく追加されたstd::promisestd::futureについてメモ。

future/promiseの基本

両者ともに標準ヘッダ <future> にて定義されるクラステンプレートであり、「別スレッドでの処理完了を待ち、その処理結果を取得する」といった非同期処理を実現するための部品*1

promiseオブジェクトとそこから取り出したfutureオブジェクトは内部的に同一の shared state を参照しており、この shared state を介して処理結果の受け渡しやスレッド間同期を実現する*3

#include <thread>
#include <future>

void func(std::promise<double> p, double x)
{
  try {
    double ret = /* 何らかの計算 */;
    p.set_value(ret);  // (2a) promiseに戻り値を設定
  } catch (...) {
    p.set_exception(std::current_exception());  // (2b) promiseに例外を設定
  }
}

int main()
{
  std::promise<double> p;
  std::future<double> f = p.get_future();

  double x = 3.14159;
  std::thread th(func, std::move(p), x);  // (1) 別スレッドで関数funcを実行

  /* 自スレッドでの処理 */;

  try {
    double result = f.get();  // (3a) promiseに設定された値を取得(別スレッドでの処理完了を待機)
  } catch (...) {
    // (3b) promiseに設定された例外が再throwされる
  }

  th.join();  // (4) 別スレッドの完了待ち
  // future/promiseによって既に必要な同期はとられているが、thread::join()を呼ばずに
  // thオブジェクトのデストラクタが呼ばれると、std::terminate()が呼び出されてしまう。
  return 0;
}

future/promiseクラステンプレートの特殊化

future/promiseクラステンプレートでは、2つのテンプレート特殊化(lvalue reference型による部分特殊化, void型による特殊化)が提供される。promise::set_value()future::get()の引数/戻り値が異なる。

// R(プライマリテンプレート)
void promise::set_value(const R& r);
void promise::set_value(R&& r);
R future::get();
// R&
void promise<R&>::set_value(R& r);
R& future<R&>::get();
// void
void promise<void>::set_value();
void future<void>::get();

例外future_errorとエラーコード

future/promiseに対する操作でエラーが生じた場合、例外std::future_errorが送出される。このfuture_errorオブジェクトにはエラーコード(std::future_errc列挙型)が格納されており、例外の発生原因を確認できる。

標準ヘッダ <future> では、future関連のエラーコードとして下記4つを定義している。