async、future、packaged_task、promise

一.async、future創建後臺任務並返回值

希望線程返回一個結果
std::async是個函數模板,用來啓動一個異步任務。什麼叫“啓動一個異步任務”,就是自動創建一個線程並開始執行對應的線程入口函數,它返回一個std::future對象,這個std::future對象裏面就含有線程函數返回的結果,我們可以通過調用std::future對象的成員函數get()來獲取結果。當調用future對象的get()成員函數時,會阻塞到這行,直到線程執行結束並返回,只能調用一次

異步任務和多線程的區別?
當我們在遇到需要長時間執行的任務時候,比如讀取一個文件,遠程服務調用。這些功能都會阻塞主線程,造成主線程卡死,從而造成一種軟件崩潰的假象。多線程技術是實現異步任務的一種實現。

我們還可以額外地向std::async()傳遞一個參數,該參數類型是std::launch類型(枚舉類型),達到一些特殊的目的。

  • std::launch::deferred: 表示線程入口函數調用被延遲到std::future的wait()或者get()函數調用時才執行。那如果wait()或者get()沒有沒調用,那麼線程會執行嗎?線程沒有創建,是在主線程中進行調用的???(此處老師的演示是在主線程中執行了,我自己的實驗這個入口函數沒有被執行)

  • std::launch::async:在調用async函數的時候就開始創建線程。默認使用這個標記。

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;

class A{
    public:
    int mythread(int mypar){
        cout<<mypar<<endl;
        cout<<"mythread() start "<<"threadid = "<<this_thread::get_id()<<endl;
        chrono::milliseconds dura(50000); //定義一個5s的時間
        this_thread::sleep_for(dura);
        cout<<"mythread() end "<<"threadid = "<<this_thread::get_id()<<endl;
        return 5;
    }
};
int mythread(){
    cout<<"mythread() start "<<"threadid = "<<this_thread::get_id()<<endl;
    chrono::milliseconds dura(50000); //定義一個5s的時間
    this_thread::sleep_for(dura);
    cout<<"mythread() end "<<"threadid = "<<this_thread::get_id()<<endl;
    return 5;
}
int main()
{
    A myobj;
    int t = 12;
    cout<<"main() start "<<"threadid = "<<this_thread::get_id()<<endl;
    //future<int> result = async(mythread); //創建一個線程並執行,不會阻塞到這裏
    future<int> result = async(launch::deferred,&A::mythread,ref(myobj),t); 
    cout<<"continue.....~"<<endl;
    int def = 0;
    //result.wait(); //等待線程返回,並不返回結果
   //cout<<result.get()<<endl; //阻塞在這裏,等待mythread()線程執行完
    cout<<"I love China!!"<<endl;
    return 0;
}

二.packaged_task

目的:打包任務,把任務包裝起來

std::packaged_task是個模板類,它的模板參數是各種可調用對象;通過std::packaged_task來把各種可調用對象包裝起來,方便將來作爲線程入口函數來調用。

packaged_task包裝起來的可調用對象還可以直接調用,所以從這個角度來講,packaged_task對象,也是一個可調用對象。

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;


 
int mythread(int mypar) //線程入口函數
{
	cout << mypar << endl;
	cout << "mythread2 start" << "threadid= " << std::this_thread::get_id() << endl; //打印線程id
 
	std::chrono::milliseconds dura(5000); //定一個5秒的時間
	std::this_thread::sleep_for(dura);  //休息一定時長
 
	cout << "mythread2 end" << "threadid= " << std::this_thread::get_id() << endl; //打印線程id
 
	return 5;
}

int main()
{
    cout << "main" << "threadid= " << std::this_thread::get_id() << endl;
    packaged_task<int(int)> mobj(mythread); //把函數mythread通過packaged_task包裝起來
   // mobj(1);  //1)直接調用,並沒有創建線程,相當於函數調用
    thread t1(ref(mobj), 1); //2)創建線程調用
    t1.join();
    future<int> result = mobj.get_future();//packaged_task和future綁定,拿到一個將來的值
    cout<<result.get()<<endl;
    return 0;
}

三.promise

std::promise 類模板,我們能夠在某個線程中給它賦值,然後我們可以在其他線程中把這個值取出來用。

總結:通過promise保存一個值,在將來某時刻我們通過把一個future綁定到這個promise上來得到這個綁定的值。

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;
 
void mythread(promise<int> &t, int calc) //線程入口函數
{
    //進行一系列複雜的操作
    calc++;
    std::chrono::milliseconds dura(5000); //定一個5秒的時間
	std::this_thread::sleep_for(dura);  //休息一定時長

    //計算出結果,將結果保存到promise對象中
    t.set_value(calc); 
}

void mythread2(future<int> &t){
    auto result = t.get();
	cout <<"mythread result = " << result<<endl;
}
int main()
{
    promise<int> m; 
    thread t1(mythread,ref(m),1);
    t1.join();
    //獲取結果值
    future<int> result = m.get_future();  //promise和future綁定,拿到一個將來的值
    
    thread t2(mythread2,ref(result)); //future傳遞給其他線程
    t2.join();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章