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");
}