C++并發(fā)高級接口std::async和std::future

std::async可以讓一個可調(diào)用對象在一個獨立線程中運行,std::future允許你等待線程結(jié)束并獲取其結(jié)果,下面代碼中,async嘗試將函數(shù)立刻異步啟動于一個分離的線程,然后返回一個future對象允許你取得函數(shù)結(jié)果或異常。

當future對象的get方法被調(diào)用時,以下三種事情之一會發(fā)生:

  • 如果函數(shù)被async啟動于一個分離線程中并且已結(jié)束,你會立刻獲得結(jié)果。
  • 如果函數(shù)被async啟動于一個分離線程中但還未結(jié)束,get會等待函數(shù)結(jié)束后獲得結(jié)果。
  • 如果函數(shù)尚未啟動,它會被強迫啟動如同一個同步調(diào)用,get會等待函數(shù)結(jié)束后獲得結(jié)果。
#include <future>
#include <thread>
#include <chrono>

int printTag(const string& tag)
{
    int ret = 0;
    for (int i = 0; i < 10; ++i) {
        this_thread::sleep_for(chrono::milliseconds(100));
        cout << tag;
        ret += i;
    }
    return ret;
}

int main()
{
    //babababaababbababaab90
    future<int> result1(async([] {return printTag("a"); }));
    int result2 = printTag("b");
    cout << result1.get() + result2 << endl;
    system("pause");
}

async可以使用launch策略async要求明確以異步方式啟動目標函數(shù),如果異步調(diào)用在此無法實現(xiàn)(例如當前環(huán)境不支持多線程或無法創(chuàng)建新的線程),程序會拋出一個std::system_error異常。

future<int> result1(async(launch::async, [] {return printTag("a"); }));

使用launch策略deferred可以強制延緩執(zhí)行目標函數(shù)直到對future對象調(diào)用get或wait。

int main()
{
    //bbbbbbbbbbaaaaaaaaaa90
    future<int> result1(async(launch::deferred,[] {return printTag("a"); }));
    int result2 = printTag("b");
    cout << result1.get() + result2 << endl;
    system("pause");
}

如果不將async的結(jié)果賦值出去(deferred策略除外),調(diào)用者會在此等待直到目標函數(shù)結(jié)束。

int main()
{
    //aaaaaaaaaabbbbbbbbbb
    async([] {return printTag("a"); });
    int result2 = printTag("b");
    system("pause");
}

線程中未被處理的異常會被捕捉到future對象中,然后在調(diào)用get時再次拋出。

void throwExceptionFunc()
{
    try {
        throw exception();
    }
    catch (...) {
        cout << "catch exception in sub thread" << endl;
    }
}

int main()
{
    future<void> result1(async(throwExceptionFunc));
    try {
        result1.get();
    }catch (...) {
        cout << "catch exception in main thread" << endl;
    }
    system("pause");
}

一個future對象只能調(diào)用一次get方法,在那之后future對象就處于無效狀態(tài),這種狀態(tài)可以用valid方法來檢測。

future還提供一組接口允許我們等待后臺操作完成而不需要處理其結(jié)果,這些接口可以被調(diào)用一次以上,分別是wait,wait_for(等待一段時間),wait_until(等待直到某特定時間點到達),這些接口不會拋出線程中未處理的異常。

wait_for,wait_until會返回以下三種值:

  • future_status::deferred:async使用了deferred策略,且沒調(diào)用過wait或get方法,這種情況下會立刻返回。
  • future_status::timeout:操作被異步啟動但尚未結(jié)束,而等待的時間已到。
  • future_status::ready:操作成功完成。
void printFunc()
{
    while (true) {
        this_thread::sleep_for(chrono::seconds(1));
        cout << "runing..." << endl;
    }
}

int main()
{
    
    future<void> result1(async(printFunc));
    cout << (int)result1.wait_for(chrono::seconds(10))<< endl;
    cout << "wait finished!"<<endl;
    system("pause");
}

使用lambda時可以使用值捕獲或引用捕獲傳遞實參給函數(shù),也可以直接使用async傳遞實參(等同于值捕獲)。

void modifyStr(string& str)
{
    str+= "_modifyed";
}

void printStr(const string& str)
{
    cout << str << endl;
}

int main()
{
 
    string testStr = "hello";
    auto result1=async(printStr, testStr);//使用async傳遞實參
    result1.wait();

    auto result2 = async([=]()mutable{modifyStr(testStr); });//值捕獲
    result2.wait();
    cout << testStr << endl;//hello

    auto result3 = async([&] {modifyStr(testStr); });//引用捕獲
    result3.wait();
    cout << testStr << endl;//hello_modifyed
    system("pause");
}

future只能調(diào)用一次get方法,而shared_future可以多次調(diào)用get方法(返回相同結(jié)果),這在多個線程想處理同一個結(jié)果時非常有用。

int queryNumber()
{
    cout << "read number:";
    int num;
    cin >> num;
    if (!cin) {
        return 0;
    }
    return num;
}
 

void printChar(char c, shared_future<int> f)
{
    int num = f.get();
    for (int i = 0; i < num; i++) {
        this_thread::sleep_for(chrono::milliseconds(100));
        cout << c;
    }
}

int main()
{
 
    shared_future<int> f = async(queryNumber);
    auto f1 = async(launch::async, printChar, 'A', f);
    auto f2 = async(launch::async, printChar, 'B', f);
    auto f3 = async(launch::async, printChar, 'C', f);
    f1.wait();
    f2.wait();
    f3.wait();
    system("pause");
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容