1、std::async、std::future創(chuàng)建后臺任務(wù)并返回值
std::async: 是一個函數(shù)模板,用來啟動一個異步任務(wù),啟動起來一個異步任務(wù)之后,它返回一個std::future對象,這個對象是個類模板。
什么叫“啟動一個異步任務(wù)”?就是自動創(chuàng)建一個線程,并開始執(zhí)行對應(yīng)的線程入口函數(shù),它返回一個std::future對象,這個std::future對象中就含有線程入口函數(shù)所返回的結(jié)果,我們可以通過調(diào)用future對象的成員函數(shù)get()來獲取結(jié)果。
“future”將來的意思,也有人稱呼std::future提供了一種訪問異步操作結(jié)果的機制,就是說這個結(jié)果你可能沒辦法馬上拿到,但是在不久的將來,這個線程執(zhí)行完畢的時候,你就能夠拿到結(jié)果了,所以,大家這么理解:future中保存著一個值,這個值是在將來的某個時刻能夠拿到。
std::future對象的get()成員函數(shù)會等待線程執(zhí)行結(jié)束并返回結(jié)果,拿不到結(jié)果它就會一直等待,感覺有點像join()。但是,它是可以獲取結(jié)果的。
std::future對象的wait()成員函數(shù),用于等待線程返回,本身并不返回結(jié)果,這個效果和 std::thread 的join()更像。
#include <iostream>
#include <future>
using namespace std;
class A {
public:
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);//定義一個5秒的時間
std::this_thread::sleep_for(dura);//創(chuàng)建一個線程并開始執(zhí)行,綁定關(guān)系
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;//卡在這里等待mythread()執(zhí)行完畢,拿到結(jié)果
return mypar;
}
};
int mythread() {
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);//定義一個5秒的時間
std::this_thread::sleep_for(dura);//創(chuàng)建一個線程并開始執(zhí)行,綁定關(guān)系
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;//卡在這里等待mythread()執(zhí)行完畢,拿到結(jié)果
return 5;
}
int main() {
A a;
int tmep = 12;
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
std::future<int> result1 = std::async(mythread);
cout << "continue........" << endl;
cout << result1.get() << endl; //卡在這里等待mythread()執(zhí)行完畢,拿到結(jié)果,只能使用一次
//類成員函數(shù)
std::future<int> result2 = std::async(&A::mythread, &a, temp); //第二個參數(shù)是對象引用才能保證線程里執(zhí)行的是同一個對象
cout << result2.get() << endl;
//或者result2.wait(); //等待線程返回,本身不返回結(jié)果
cout << "good luck" << endl;
return 0;
}
我們通過向std::async()傳遞一個參數(shù),該參數(shù)是std::launch類型(枚舉類型),來達到一些特殊的目的:
- std::lunch::deferred:
(defer推遲,延期)表示線程入口函數(shù)的調(diào)用會被延遲,一直到std::future的wait()或者get()函數(shù)被調(diào)用時(由主線程調(diào)用)才會執(zhí)行;如果wait()或者get()沒有被調(diào)用,則不會執(zhí)行。
重點:實際上根本就沒有創(chuàng)建新線程。std::launch::deferred意思時延遲調(diào)用,并沒有創(chuàng)建新線程,是在主線程中調(diào)用的線程入口函數(shù)。
#include <iostream>
#include <future>
using namespace std;
class A {
public:
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return mypar;
}
};
int main() {
A a;
int temp = 12;
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
cout << "continue........" << endl;
std::future<int> result1 = std::async(std::launch::deferred, &A::mythread, &a, temp);
cout << result1.get() << endl;
//或者result2.wait();
cout << "I love China!" << endl;
return 0;
}
- std::launch::async,在調(diào)用async函數(shù)的時候就開始創(chuàng)建新線程,不添加標記,默認用的就是默認值是 std::launch::async | std::launch::deferred 標記。
int main() {
A a;
int temp = 12;
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
cout << "continue........" << endl;
std::future<int> result1 = std::async(std::launch::async, &A::mythread, &a, temp);//使用std::launch::async標記
cout << result1.get() << endl;
//或者result2.wait();
cout << "I love China!" << endl;
return 0;
}
- 同時使用std::launch::async和std::lunch::deferred標記,并不能在新線程中延遲調(diào)用。
2、std::packaged_task:打包任務(wù),把任務(wù)包裝起來
類模板,它的模板參數(shù)是各種可調(diào)用對象,通過packaged_task把各種可調(diào)用對象包裝起來,方便將來作為線程入口函數(shù)來調(diào)用。
#include <thread>
#include <iostream>
#include <future>
using namespace std;
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main() {
cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
//我們把函數(shù)mythread通過packaged_task包裝起來
//參數(shù)是一個int,返回值類型是int
//方法1
std::packaged_task<int(int)> mypt(mythread);
std::thread t1(std::ref(mypt), 1);//線程開始執(zhí)行
t1.join();//等待線程執(zhí)行完畢
std::future<int> result = mypt.get_future();
//std::future對象里包含有線程入口函數(shù)的返回結(jié)果,這里result保存mythread返回的結(jié)果。
cout << result.get() << endl;
return 0;
}
可調(diào)用對象可由函數(shù)換成lambda表達式
int main() {
//方法2,用lambda表達式
std::packaged_task<int(int)> mypt([](int mypar){
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
});
std::thread t1(std::ref(mypt), 1);
t1.join();
std::future<int> result = mypt.get_future();
//std::future對象里包含有線程入口函數(shù)的返回結(jié)果,這里result保存mythread返回的結(jié)果。
cout << result.get() << endl;
cout << "I love China!" << endl;
return 0;
}
packaged_task包裝起來的可調(diào)用對象還可以直接調(diào)用,從這個角度來講,packaged_task對象也是一個可調(diào)用對象
lambda的直接調(diào)用
int main() {
//方法2,用lambda表達式
std::packaged_task<int(int)> mypt([](int mypar){
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
});
//packaged_task包裝起來的可調(diào)用對象還可以直接調(diào)用,所以從這個角度來講,pakcaged_task對象,也是一個可調(diào)用對象;
mypt(105);//直接調(diào)用,相當于函數(shù)調(diào)用
std::future<int> result=mypt.get_future();
cout<<result.get()<<endl;
return 0;
}
包裝后存放容器里
vector<std::packaged<int(int)>> mytasks;
int main() {
//方法2,用lambda表達式
std::packaged_task<int(int)> mypt([](int mypar){
cout << mypar << endl;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
});
mytasks.push_back(std::move(mypt));//入容器,進去用了移動語義,入進去之后mypt就為空
std::packaged_task<int(int)>mypt2;
auto iter=mytask.begin();
mypt2=std::move(*iter);//移動語義
mytasks.erase(iter);//刪除第一個元素,迭代已經(jīng)失效了,所以后續(xù)代碼不可以再使用iter
mypt2(105);//直接調(diào)用,相當于函數(shù)調(diào)用
std::future<int> result=mypt2.get_future();
cout<<result.get()<<endl;
return 0;
}
3、std::promise
類模板,我們能夠在某個線程中給它賦值,然后我們可以在其他線程中,把這個值取出來
#include <thread>
#include <iostream>
#include <future>
using namespace std;
void mythread(std::promise<int> &tmpp, int clac) {
//做一系列復(fù)雜的操作
clac++;
clac *=10;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
int result = clac;//保存結(jié)果
tmp.set_value(result); //結(jié)果保存到了tmp這個對象中
return;
}
int main() {
std::promise<int> myprom;
std::thread t1(mythread, std::ref(myprom), 180);
t1.join(); //在這里線程已經(jīng)執(zhí)行完了
std::future<int> fu1 = myprom.get_future(); //promise和future綁定,用于獲取線程返回值
auto result = fu1.get();//get只能調(diào)用1次
cout << "result = " << result << endl;
cout<<"I love China!"<<endl;
}
總結(jié):通過promise保存一個值,在將來某個時刻我們通過把一個future綁定到這個promise上,來得到綁定的值
使用兩個子進程
#include <thread>
#include <iostream>
#include <future>
using namespace std;
void mythread(std::promise<int> &tmpp, int clac) {
//做一系列復(fù)雜的操作
clac++;
clac *=10;
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
int result = clac;//保存結(jié)果
tmp.set_value(result); //結(jié)果保存到了tmp這個對象中
return;
}
void mythread2(std::future<int> &tmpf){
auto result=tmpf.get();
cout<<"mythread2.result"<<result<<endl;
return;
}
int main() {
std::promise<int> myprom;
std::thread t1(mythread, std::ref(myprom), 180);
t1.join(); //在這里線程已經(jīng)執(zhí)行完了
std::future<int> fu1 = myprom.get_future(); //promise和future綁定,用于獲取線程返回值
std::thread t2(mythread2,std::ref(ful));
t2.join();//等mythread2線程執(zhí)行完畢
cout<<"I love China!"<<endl;
}
總結(jié):第一個線程1(t1) 計算了一個結(jié)果,結(jié)果通過future對象給到第二個線程2(t2)。
注意:使用thread時,必須 join() 或者 detach() 否則程序會報異常文章來源:http://www.zghlxwxcb.cn/news/detail-662720.html
3、小結(jié)
我們學(xué)習(xí)這些東西的目的并不是,要把他們都用到實際開發(fā)中。
相反,如果我們能夠用最少的東西寫出一個穩(wěn)定的,高效的多線程程序,更值得贊賞。
我們?yōu)榱顺砷L必須閱讀一些高手寫的代碼,從而實現(xiàn)自己代碼的積累;文章來源地址http://www.zghlxwxcb.cn/news/detail-662720.html
到了這里,關(guān)于C++11并發(fā)與多線程筆記(9) async、future、packaged_task、promise的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!