名前空間
変種
操作

std::async

From cppreference.com
< cpp‎ | thread
 
 
並行性サポートライブラリ
スレッド
(C++11)
(C++20)
this_thread 名前空間
(C++11)
(C++11)
(C++11)
協調的なキャンセル
排他制御
(C++11)
汎用ロック管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件変数
(C++11)
セマフォ
ラッチとバリア
(C++20)
(C++20)
future
(C++11)
(C++11)
async
(C++11)
(C++11)
安全なメモリ解放 (Safe Reclamation)
(C++26)
ハザードポインタ
アトミック型
(C++11)
(C++20)
アトミック型の初期化
(C++11)(C++20で非推奨)
(C++11)(C++20で非推奨)
メモリオーダー
(C++11)(C++26で非推奨)
アトミック操作のためのフリー関数
アトミックフラグのためのフリー関数
 
ヘッダ <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,

                                    F&& f, Args&&... args );
(2) (C++11以降)

関数テンプレートstd::asyncは、関数fを非同期(潜在的にはスレッドプールの一部である別スレッドで)に実行し、その関数呼び出しの結果を最終的に保持するstd::futureを返します。

1)policystd::launch::async | std::launch::deferredとして呼び出された場合(2)と同様に振る舞います。
2)指定された起動ポリシー(下記参照)に従って、引数argsとともに呼び出される関数fを呼び出します。

std::asyncの戻り型はstd::future<V>です。ここでV

typename std::result_of<typename std::decay<F>::type(
                        typename std::decay<Args>::type...)>::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)),
       decay-copy(std::forward<Args>(args))...)

(C++23まで)

std::invoke(auto(std::forward<F>(f)),
            auto(std::forward<Args>(args))...)

(C++23から)

を、std::threadオブジェクトで表される新しい実行スレッド内で行うかのように呼び出します。

decay-copyの呼び出しは、現在のスレッドで評価されます。

(C++23まで)

autoによって生成された値は、現在のスレッドで具現化されます。

(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まで)
  • gは、auto(std::forward<F>(f))の格納された値であり、
  • xyzは、auto(std::forward<Args>(args))...の格納されたコピーです。
(C++23から)
  • 結果または例外は、返されたstd::futureに関連付けられた共有状態に配置され、その後準備完了となります。同じstd::futureへのそれ以降のすべてのアクセスは、直ちに結果を返します。

[編集] その他のポリシー

policystd::launch::asyncstd::launch::deferredも、実装定義のポリシーフラグも設定されていない場合、動作は未定義です。

[編集] ポリシーの選択

複数のフラグが設定されている場合、どのポリシーが選択されるかは実装定義です。デフォルト(policystd::launch::asyncstd::launch::deferredの両方のフラグが設定されている)の場合、標準は利用可能な並列処理を利用し、追加のタスクを遅延させることを推奨します(必須ではありません)。

std::launch::asyncポリシーが選択された場合、

  • このstd::async呼び出しによって作成された共有状態を共有する非同期返り値オブジェクトに対する待機関数呼び出しは、関連付けられたスレッドが完了するまでブロックされます(結合されたかのように)、またはタイムアウトします。
  • 関連付けられたスレッドの完了は、共有状態を待機している最初の関数からの正常な復帰、または共有状態を解放する最後の関数からの復帰のいずれか早い方と同期します。

[編集] 例外

スローする

  • 内部データ構造のメモリを割り当てられない場合、std::bad_alloc、または
  • policy == std::launch::asyncであり、実装が新しいスレッドを開始できない場合、エラー条件std::errc::resource_unavailable_try_againとともにstd::system_error
    • policystd::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 2100
std::launch::asyncポリシーが使用された場合、
許可
時間待ち関数がタイムアウトできなかった。 C++11 LWG 2120
標準
この場合の動作は
未定義となる
または実装定義のポリシーが設定されていない場合の動作が不明確。 C++11 LWG 2186
遅延評価から返された値とスローされた例外がどのように処理されるか不明確。
これらは
共有状態に格納される。
LWG 2752 C++11 内部データ構造のメモリが割り当てられない場合、std::asyncstd::bad_allocをスローしない可能性がある。
内部データ構造のメモリが割り当てられない場合
スローする
LWG 3476 C++20 (Fの)デコードされた型と引数の型
が直接ムーブ構築可能である必要があった。
これらの要件を削除した。[1]
  1. ムーブ構築可能性は、std::is_constructible_vによって間接的に要求されています。

[編集] 関連項目

(C++11)
非同期に設定される値を待機する
(クラステンプレート) [編集]
C++ドキュメント (実行サポートライブラリ)
English 日本語 中文(简体) 中文(繁體)