C++11標準ライブラリのstd::async
関数を実際に利用するときの注意点メモ。
2012年2月現在の結論:
gcc系
gcc 4.6.2, gcc 4.7-20120121(experimental) のC++標準ライブラリ実装では、launch::async
ポリシーを単体で指定した場合のみ新スレッドによる並行処理が行われる。それ以外の既定の起動ポリシーやlaunch::deferred
ポリシー指定の場合は、全て遅延関数として扱われる。
// 標準ヘッダfutureの内部実装 template<typename F, typename... Args> future<〜> async(launch policy, F&& f, Args&&... args) { if ((policy & (launch::async|launch::deferred)) == launch::async) { /* 新スレッド上で処理開始 */ } else { /* 遅延関数として扱う */ } }
gccのこの実装はC++11標準規格に準拠しているものの、プログラマが期待する動作とは異なる可能性が高い。必ず別スレッド上で並行処理される必要があるなら、明示的にlaunch::async
ポリシーを指定すること。
#include <future> // 処理1, 2, 3が並行処理されることを期待したコードだが... auto h1 = std::async([&]{ /* 処理1 */ }); auto h2 = std::async([&]{ /* 処理2 */ }); auto h3 = std::async([&]{ /* 処理3 */ }); // gccでは下記getメンバ関数呼び出しのタイミングで単純に逐次処理される。 h1.get(); h2.get(); h3.get();
VisualC++系
MSVC10はC++標準スレッドライブラリをサポートしない。
次期MSVC11では、公式ブログにて「std::async
関数でもConcRT(Concurrency Runtime)フレームワークを利用する」と言及されており期待はできそう。
サードパーティライブラリ
just::threadライブラリでは、プログラマが期待するインテリジェントな動作が実装がされているとのこと。(情報のみ)
The main change with this release is an enhancement to the std::async implementation. With this enhanced scheduler, the default launch policy (std::launch::async | std::launch::deferred) will defer forcing a decision until either enough resources become available to schedule the task as std::launch::async, or the task is forced to be scheduled as std::launch:deferred by a call to a waiting function (get(), wait(), wait_for() or wait_until()). This will allow more tasks to be scheduled as std::launch::async overall, and allow your application to make better use of the available hardware concurrency.
http://www.stdthread.co.uk/forum/index.php/topic,87.msg177.html
また下記C++ライブラリは、タスクベースのスケジューリング機能を提供する。これらはstd::async
関数と直接的な関係はないが、プログラマがasync関数の既定起動ポリシーに対して期待する動作に近いことが実現できる。
関連URL