std::async
| ヘッダ <future> で定義 |
||
| template< class F, class... Args > std::future</* 以下参照 */> async( F&& f, Args&&... args ); |
(1) | (C++11以降) |
| template< class F, class... Args > std::future</* 以下参照 */> async( std::launch policy, |
(2) | (C++11以降) |
関数テンプレートstd::asyncは、関数fを非同期(潜在的にはスレッドプールの一部である別スレッドで)に実行し、その関数呼び出しの結果を最終的に保持するstd::futureを返します。
std::asyncの戻り型はstd::future<V>です。ここでVは
|
typename std::result_of<typename std::decay<F>::type( |
(C++17まで) |
|
std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>. |
(C++17以降) |
|
以下のいずれかの条件が満たされる場合、プログラムは不適格です。
|
(C++20まで) |
|
以下のいずれかがfalseの場合、プログラムは不正形式となります。
|
(C++20以降) |
std::asyncの呼び出しは、fの呼び出しと同期し、fの完了は、共有状態が準備完了になることより前に順序付けられています。
目次 |
[編集] パラメータ
| f | - | 呼び出すCallableオブジェクト |
| args | - | fに渡すパラメータ |
| policy | - | 実行方法を制御するビットマスク値 |
[編集] 戻り値
std::asyncのこの呼び出しによって作成された共有状態を参照するstd::future。
[編集] 起動ポリシー
[編集] 非同期起動
asyncフラグが設定されている場合(つまり、(policy & std::launch::async) != 0)、std::asyncは以下を呼び出します。
|
INVOKE(decay-copy(std::forward<F>(f)), |
(C++23まで) |
|
std::invoke(auto(std::forward<F>(f)), |
(C++23から) |
を、std::threadオブジェクトで表される新しい実行スレッド内で行うかのように呼び出します。
|
|
(C++23まで) |
|
|
(C++23から) |
関数fが値を返したり例外をスローしたりした場合、それはstd::asyncが呼び出し元に返すstd::futureを通じてアクセス可能な共有状態に格納されます。
[編集] 遅延起動
deferredフラグが設定されている場合(つまり、(policy & std::launch::deferred) != 0)、std::asyncは以下を共有状態に格納します。
|
decay-copy(std::forward<F>(f))およびdecay-copy(std::forward<Args>(args))...。 |
(C++23まで) |
|
auto(std::forward<F>(f))およびauto(std::forward<Args>(args))...を共有状態に格納します。 |
(C++23から) |
遅延評価が実行されます。
- 呼び出し元に
std::asyncが返したstd::futureに対する最初の非時間待ち関数呼び出しにより、INVOKE(std::move(g), std::move(xyz))が、待機関数を呼び出したスレッド(必ずしも最初にstd::asyncを呼び出したスレッドである必要はない)で評価されます。ここで
|
(C++23まで) |
|
(C++23から) |
- 結果または例外は、返された
std::futureに関連付けられた共有状態に配置され、その後準備完了となります。同じstd::futureへのそれ以降のすべてのアクセスは、直ちに結果を返します。
[編集] その他のポリシー
policyでstd::launch::asyncもstd::launch::deferredも、実装定義のポリシーフラグも設定されていない場合、動作は未定義です。
[編集] ポリシーの選択
複数のフラグが設定されている場合、どのポリシーが選択されるかは実装定義です。デフォルト(policyでstd::launch::asyncとstd::launch::deferredの両方のフラグが設定されている)の場合、標準は利用可能な並列処理を利用し、追加のタスクを遅延させることを推奨します(必須ではありません)。
std::launch::asyncポリシーが選択された場合、
- この
std::async呼び出しによって作成された共有状態を共有する非同期返り値オブジェクトに対する待機関数呼び出しは、関連付けられたスレッドが完了するまでブロックされます(結合されたかのように)、またはタイムアウトします。 - 関連付けられたスレッドの完了は、共有状態を待機している最初の関数からの正常な復帰、または共有状態を解放する最後の関数からの復帰のいずれか早い方と同期します。
[編集] 例外
スローする
- 内部データ構造のメモリを割り当てられない場合、std::bad_alloc、または
-
policy == std::launch::asyncであり、実装が新しいスレッドを開始できない場合、エラー条件std::errc::resource_unavailable_try_againとともにstd::system_error。policyがstd::launch::async | std::launch::deferredであるか、追加のビットが設定されている場合、この場合、遅延起動または実装定義のポリシーにフォールバックします。
[編集] 注記
実装は、デフォルトの起動ポリシーで追加の(実装定義の)ビットを有効にすることにより、std::asyncの最初のオーバーロードの動作を拡張する場合があります。
実装定義の起動ポリシーの例としては、同期ポリシー(std::async呼び出し内で即座に実行)やタスクポリシー(std::asyncに似ているが、スレッドローカルはクリアされない)があります。
std::asyncから取得したstd::futureが移動されず、参照にバインドされない場合、std::futureのデストラクタは、非同期操作が完了するまでフルエクスプレッションの終端でブロックし、実質的に次のようなコードを同期させます。
std::async(std::launch::async, []{ f(); }); // temporary's dtor waits for f() std::async(std::launch::async, []{ g(); }); // does not start until f() completes
std::async以外の手段で取得されたstd::futureのデストラクタは、決してブロックしないことに注意してください。
[編集] 例
#include <algorithm> #include <future> #include <iostream> #include <mutex> #include <numeric> #include <string> #include <vector> std::mutex m; struct X { void foo(int i, const std::string& str) { std::lock_guard<std::mutex> lk(m); std::cout << str << ' ' << i << '\n'; } void bar(const std::string& str) { std::lock_guard<std::mutex> lk(m); std::cout << str << '\n'; } int operator()(int i) { std::lock_guard<std::mutex> lk(m); std::cout << i << '\n'; return i + 10; } }; template<typename RandomIt> int parallel_sum(RandomIt beg, RandomIt end) { auto len = end - beg; if (len < 1000) return std::accumulate(beg, end, 0); RandomIt mid = beg + len / 2; auto handle = std::async(std::launch::async, parallel_sum<RandomIt>, mid, end); int sum = parallel_sum(beg, mid); return sum + handle.get(); } int main() { std::vector<int> v(10000, 1); std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n'; X x; // Calls (&x)->foo(42, "Hello") with default policy: // may print "Hello 42" concurrently or defer execution auto a1 = std::async(&X::foo, &x, 42, "Hello"); // Calls x.bar("world!") with deferred policy // prints "world!" when a2.get() or a2.wait() is called auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!"); // Calls X()(43); with async policy // prints "43" concurrently auto a3 = std::async(std::launch::async, X(), 43); a2.wait(); // prints "world!" std::cout << a3.get() << '\n'; // prints "53" } // if a1 is not done at this point, destructor of a1 prints "Hello 42" here
実行結果の例
The sum is 10000 43 world! 53 Hello 42
[編集] 不具合報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 2021 | C++11 | 遅延ケースの戻り型と引数の値カテゴリが不明確。 遅延ケースの引数の値カテゴリが不明確。 |
戻り型を修正し、 Rvalueが使用されることを明確化。 |
| LWG 2078 | C++11 | std::system_errorがstd::launch::async以外の起動ポリシーを指定した場合にスローされる可能性があるかどうか不明確。 |
スローされるのは policy == std::launch::async |
| の場合のみ。 | C++11 | LWG 2100std::launch::asyncポリシーが使用された場合、 |
許可 |
| 時間待ち関数がタイムアウトできなかった。 | C++11 | LWG 2120 標準 |
この場合の動作は 未定義となる |
| または実装定義のポリシーが設定されていない場合の動作が不明確。 | C++11 | LWG 2186 遅延評価から返された値とスローされた例外がどのように処理されるか不明確。 |
これらは 共有状態に格納される。 |
| LWG 2752 | C++11 | 内部データ構造のメモリが割り当てられない場合、std::asyncはstd::bad_allocをスローしない可能性がある。内部データ構造のメモリが割り当てられない場合 |
スローする |
| LWG 3476 | C++20 | (Fの)デコードされた型と引数の型 が直接ムーブ構築可能である必要があった。 |
これらの要件を削除した。[1] |
- ↑ ムーブ構築可能性は、
std::is_constructible_vによって間接的に要求されています。
[編集] 関連項目
| (C++11) |
非同期に設定される値を待機する (クラステンプレート) |
| C++ドキュメント (実行サポートライブラリ)
| |