1. 程式人生 > >[轉]c++11 多執行緒 future/promise

[轉]c++11 多執行緒 future/promise

[轉自 https://blog.csdn.net/jiange_zh/article/details/51602938]

1. < future >標頭檔案簡介


Classes
std::future
std::future_error
std::packaged_task
std::promise
std::shared_future
Functions
std::async
std::future_category


2. std::future

簡單來說,std::future提供了一種訪問非同步操作結果的機制。

從字面意思看,它表示未來。通常一個非同步操作我們是不能馬上就獲取操作結果的,只能在未來某個時候獲取。我們可以以同步等待的方式來獲取結果,可以通過查詢future的狀態(future_status)來獲取非同步操作的結果。future_status有三種狀態:
deferred:非同步操作還沒開始
ready:非同步操作已經完成
timeout:非同步操作超時

獲取future結果有三種方式:get、wait、wait_for,其中get等待非同步操作結束並返回結果,wait只是等待非同步操作完成,沒有返回值,wait_for是超時等待返回結果。

例子:

 1 //查詢future的狀態
 2     std::future_status status;
 3     do {
 4         status = future.wait_for(std::chrono::seconds(1));
 5         if
(status == std::future_status::deferred) { 6             std::cout << "deferred\n"; 7         } else if (status == std::future_status::timeout) { 8             std::cout << "
timeout\n"; 9         } else if (status == std::future_status::ready) { 10             std::cout << "ready!\n"; 11         } 12     } while (status != std::future_status::ready);

3. std::promise

Promise物件可儲存T型別的值,該值可被future物件讀取(可能在另一個執行緒中),這是promise提供同步的一種手段。在構造promise時,promise物件可以與共享狀態關聯起來,這個共享狀態可以儲存一個T型別或者一個由std::exception派生出的類的值,並可以通過get_future來獲取與promise物件關聯的物件,呼叫該函式之後,兩個物件共享相同的共享狀態(shared state)。
Promise物件是非同步provider,它可以在某一時刻設定共享狀態的值。
Future物件可以返回共享狀態的值,或者在必要的情況下阻塞呼叫者並等待共享狀態標識變為ready,然後才能獲取共享狀態的值。

例子:

 1 #include <iostream>       // std::cout
 2 #include <functional>     // std::ref
 3 #include <thread>         // std::thread
 4 #include <future>         // std::promise, std::future
 5 void print_int(std::future<int>& fut) {
 6     int x = fut.get(); // 獲取共享狀態的值.
 7     std::cout << "value: " << x << '\n'; // 列印 value: 10.
 8 }
 9 int main ()
10 {
11     std::promise<int> prom; // 生成一個 std::promise<int> 物件.
12     std::future<int> fut = prom.get_future(); // 和 future 關聯.
13     std::thread t(print_int, std::ref(fut)); // 將 future 交給另外一個執行緒t.
14     prom.set_value(10); // 設定共享狀態的值, 此處和執行緒t保持同步.
15     t.join();
16     return 0;
17 }

 

std::promise 建構函式

建構函式  
default(1) promise()
with alocator(2) template  promise (allocator_arg_t aa, const Alloc& alloc);
copy [deleted](3)  promise(const promise&)= delete;
move(4) promise(promise&& x) noexcept; 

1.預設建構函式,初始化一個空的共享狀態。

2.帶自定義記憶體分配器的建構函式,與預設建構函式類似,但是使用自定義分配器來分配共享狀態。
3.拷貝建構函式,被禁用。
4.移動建構函式。
另外,std::promise 的 operator= 沒有拷貝語義,即 std::promise 普通的賦值操作被禁用,operator= 只有 move 語義,所以 std::promise 物件是禁止拷貝的。

 

std::promise 成員函式

std::promise::get_future:返回一個與promise共享狀態相關聯的future物件
std::promise::set_value:設定共享狀態的值,此後promise共享狀態標識變為ready
std::promise::set_exception:為promise設定異常,此後promise的共享狀態標識變為ready
std::promise::set_value_at_thread_exit:設定共享狀態的值,但是不將共享狀態的標誌設定為 ready,當執行緒退出時該 promise 物件會自動設定為 ready(注意:該執行緒已設定promise的值,如果線上程結束之後有其他修改共享狀態值的操作,會丟擲future_error(promise_already_satisfied)異常)
std::promise::swap:交換 promise 的共享狀態

4. std::packaged_task

std::packaged_task包裝了一個可呼叫的目標(如function, lambda expression, bind expression, or another function object),以便非同步呼叫,它和promise在某種程度上有點像,promise儲存了一個共享狀態的值,而packaged_task儲存的是一個函式。

 

    std::packaged_task<int()> task([](){ return 7; });
    std::thread t1(std::ref(task));
    std::future<int> f1 = task.get_future();
    auto r1 = f1.get();1234

 

5. 小結

Promise,Future 和 Callback常常作為併發程式設計中一組非阻塞的模型。其中 Future 表示一個可能還沒有實際完成的非同步任務的【結果】,針對這個結果可以新增 Callback 以便在任務執行成功或失敗後做出對應的操作,而 Promise 交由任務執行者,任務執行者通過 Promise 可以標記任務完成或者失敗。

 

6. std::async

std::async大概的工作過程:先將非同步操作用std::packaged_task包裝起來,然後將非同步操作的結果放到std::promise中,這個過程就是創造未來的過程。外面再通過future.get/wait來獲取這個未來的結果。

可以說,std::async幫我們將std::future、std::promise和std::packaged_task三者結合了起來。

std::async的原型:

 

async(std::launch::async | std::launch::deferred, f, args...)1

第一個引數是執行緒的建立策略,預設的策略是立即建立執行緒:

std::launch::async:在呼叫async就開始建立執行緒。
std::launch::deferred:延遲載入方式建立執行緒。呼叫async時不建立執行緒,直到呼叫了future的get或者wait時才建立執行緒。
第二個引數是執行緒函式,後面的引數是執行緒函式的引數。

簡單的例子:

 

    std::future<int> f1 = std::async(std::launch::async, [](){
        return 8; 
    });

    cout<<f1.get()<<endl; //output: 8

    std::future<int> f2 = std::async(std::launch::async, [](){
        cout<<8<<endl;
    });

    f2.wait(); //output: 81234567891011           
      
---------------------
作者:jiange_zh
來源:CSDN
原文:https://blog.csdn.net/jiange_zh/article/details/51602938
版權宣告:本文為博主原創文章,轉載請附上博文連結!