天天看點

C++多線程之旅-future等待事件

目錄

      • 前言
      • future
      • 總結

前言

前一篇文章講到了關于

condition_variable

的使用,但是這種方法太過于底層了,不是很方面,而且需要對調用方進行操作。這樣對于程式員來說太過于麻煩,引入一個全新的接口,讓被調用的線程自動進行,調用線程直接調用結果就行。這就是C++引入的

future()類

,而且這種方式可以在不同線程之間傳遞資料。

我們首先假設情況現在有兩個線程,線程A等待線程B執行結果,線程B執行完成之後将結果傳回給線程A。之前在

condition_variable

裡面是線上程外定義一個全局變量,但是這樣會導緻資料不安全有洩露的風險。

future

首先看一個例子:

string fun_1()  {
    return "123";
}

int main() {
    auto x = async(fun_1);
    cout << "456";
    cout << x.get();
}
           

此時x擷取到的是

future<string>

類型,然後在調用.get()函數獲得其中包含的值。而且線程

fun_1

隻有在

.get()

時才調用。執行結果如下:

C++多線程之旅-future等待事件

這裡面有兩個函數,一個是

async

,另一個是

future

async

使用方法和

thread類

類似,但是多了一個函數參數。

async(A, B, C,....)

  • 其中這個A:是表示你是否建立一個新線程,參數類型是std::launch類型。
    • std::launch::deferred:表示該函數會延遲啟動,直到

      future

      上調用

      wait()

      get()

    • std::launch::async:表示該函數必須運作在他自己的線程上;
    • std::launch::deferred | std::launch::async:表明該函數可以有具體實作來選擇(預設最後一個);
  • B和C:分别是需要傳入的函數和函數的參數,和thread一樣,函數的參數是通過副本傳入,如果需要傳入引用則需要使用std::ref類。

future可以從異步任務中擷取結果,一般與std::async配合使用,std::async用于建立異步任務,實際上就是建立一個線程執行相應任務。

  • std::future::get擷取結果,如果調用過程中,任務尚未完成,則主線程阻塞至任務完成。
  • std::future::wait_for等待結果傳回,wait_for可設定逾時時間,如果在逾時時間之内任務完成,則傳回std::future_status::ready狀态;如果在逾時時間之内任務尚未完成,則傳回std::future_status::timeout狀态。

前面那個例子我們看了get()方法,我們來測試一下這個wait_for()方法:

string fun_2() {
    this_thread::sleep_for(chrono::seconds(3));
    return "hello";
}
int main() {
    auto x = async(fun_2);
    cout << "456  ";
    if  (x.wait_for(chrono::seconds(1)) == future_status::timeout)
        cout << "time out" << endl;
    else
        cout << x.get();
}
           

線程fun_2執行時,線程睡眠3秒,主線程僅僅隻等待1秒,就會出現傳回time_out标志。

C++多線程之旅-future等待事件

修改相應的等待時間參數之後得到的結果就是另外一個樣子了。

C++多線程之旅-future等待事件

總結

在使用異步線程時,采用future比condition_variable簡單而且無需考慮内部實作的過程。是以在使用是盡量使用這個,而且還可以實作在不同線程之間傳遞資料,避免使用全局變量提高系統安全性。