名稱空間
變體
操作

std::async

來自 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)
期值
(C++11)
(C++11)
async
(C++11)
(C++11)
安全回收
(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,該 std::future 最終將儲存該函式呼叫的結果。

1) 其行為如同呼叫 (2),其中 policystd::launch::async | std::launch::deferred
2) 根據特定的啟動策略 policy(見下文),用引數 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::future,引用此 std::async 呼叫建立的共享狀態。

[編輯] 啟動策略

[編輯] 非同步呼叫

如果設定了 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 起)

執行延遲求值(Lazy evaluation)

  • std::async 返回給呼叫者的 std::future 的非定時等待函式的第一次呼叫將在呼叫等待函式的執行緒(不必是最初呼叫 std::async 的執行緒)中評估 INVOKE(std::move(g), std::move(xyz)),其中
(直至 C++23)
(C++23 起)
  • 結果或異常被放置在與返回的 std::future 關聯的共享狀態中,然後才使其就緒。所有後續對相同 std::future 的訪問都將立即返回結果。

[編輯] 其他策略

如果在 policy 中既沒有設定 std::launch::async 也沒有設定 std::launch::deferred,也沒有設定任何實現定義的策略標誌,則行為未定義。

[編輯] 策略選擇

如果設定了多個標誌,則選擇哪種策略由實現定義。對於預設情況(std::launch::asyncstd::launch::deferred 標誌都在 policy 中設定),標準建議(但不要求)利用可用的併發性,並延遲任何額外的任務。

如果選擇了 std::launch::async 策略,

  • 對共享由 std::async 呼叫建立的共享狀態的非同步返回物件上的等待函式的呼叫將阻塞,直到關聯執行緒完成(如同已加入),或者超時;並且
  • 關聯執行緒的完成與第一次等待共享狀態的函式的成功返回,或與釋放共享狀態的最後一個函式的返回同步,以先發生者為準。

[編輯] 異常

丟擲

[編輯] 注意

實現可以透過在預設啟動策略中啟用額外的(實現定義的)位來擴充套件 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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
LWG 2021 C++11 返回型別不正確且在延遲情況下引數的
值類別不明確
已更正返回型別並
澄清使用右值
LWG 2078 C++11 不清楚如果 policy 指定了除了 std::launch::async 之外的其他啟動策略,
是否會丟擲 std::system_error
只有當 policystd::launch::async 時才可能丟擲
僅當
policy == std::launch::async 時才丟擲
LWG 2100 C++11 定時等待函式無法超時
如果使用 std::launch::async 策略
允許
LWG 2120 C++11 如果未設定標準
或實現定義的策略,則行為不明確
在這種情況下,行為是
未定義的
LWG 2186 C++11 不清楚延遲求值返回的值和丟擲的
異常如何處理
它們儲存在
共享狀態中
LWG 2752 C++11 如果無法分配內部資料結構的記憶體,std::async 可能不會丟擲 std::bad_alloc
如果無法分配內部資料結構的記憶體
丟擲
LWG 3476 C++20 (衰變後的) F 型別和引數型別
曾被直接要求為可移動構造的
已移除這些要求[1]
  1. 可移動構造性已經透過 std::is_constructible_v 間接要求。

[編輯] 另見

(C++11)
等待一個非同步設定的值
(類模板) [編輯]
C++ 文件 for 執行支援庫