描述:
std::future 可以用來擷取所有異步操作的結果,一般情況下 std::future 都會和 std::async , std::promise 或 std::packaged_task 一起使用。
std::future 有一個 valid 狀态,當且僅當其valid狀态時true時,才可以使用它,std::async , std::promise 或 std::packaged_task 建立的 std::future 都是 valid == true的 ,如果自行使用 std::future 的構造函數建立一個執行個體,那麼它一定不是 valid 的,可以把 valid 狀态當做一個 std::future 是否和某個異步任務相關聯的标志,valid == false 代表目前 std::future 實際沒有關聯任何異步任務。
因為其内部已經有關聯的異步任務了,可以把valid看作是std::future是否初始化完成的标志,一般初始化都比較快,是以正常情況下invalid狀态很少出現,一般隻在沒指定異步任務時出現。另外如果使用std::move把異步任務從某個std::future轉移給另一個,那麼之前那個std::future會變成invalid狀态。
std::future 有兩套阻塞等待函數 waitX() 和 get(), waitX()會在任務沒有執行完畢的情況下一直阻塞或者阻塞等待一段時間,但是不會改變std::future的valid狀态。
get() 會阻塞等待任務執行完畢并且傳回任務的傳回值,同時會把 std::future 的狀态變成 invalid 狀态。這個時候隻有重新做 move 或者重新通過 std::async , std::promise 或 std::packaged_task 才能再次激活 std::future。
換句話說,每個std::future 隻能 get 一次,重複 get 會導緻抛異常,進而崩潰。
鑒于不能重複 get 的問題,很多情況下我們隻和 void 傳回值的可調用對象一起使用,然後不去調用get函數,隻用wait作同步隻用。
與 std::async 一起使用
#include <future>
#include <string>
#include <mutex>
#include <stdio.h>
#include <unistd.h>
#include <thread>
#include <iostream>
std::atomic<bool> bbb{false};
int func()
{
while(!bbb){
sleep(1);
}
std::cout << "func stop" << std::endl;
return 99;
}
int main()
{
std::future<int> ret;
//沒有關聯任何任務,是以是invalid
if(ret.valid()){
std::cout << "valid" << std::endl;
}else{
std::cout << "invalid" << std::endl;
}
std::cout << "----------" << std::endl;
std::future<int> ret1 = std::async<int()>(std::launch::async,func);
if(ret1.valid()){
std::cout << "before move ret1 : valid" << std::endl;
}else{
std::cout << "before move ret1 : invalid" << std::endl;
}
ret = std::move(ret1);
if(ret1.valid()){
std::cout << "after move ret1 : valid" << std::endl;
}else{
std::cout << "after : invalid" << std::endl;
}
std::cout << "----------" << std::endl;
//關聯任務,是以是valid
if(ret.valid()){
std::cout << "valid" << std::endl;
}else{
std::cout << "invalid" << std::endl;
}
std::cout << "----------" << std::endl;
//把任務停掉,仍然是valid
bbb = true;
//等待可執行對象執行完畢,如果在wait之前已經執行完畢,那麼這裡直接傳回
ret.wait();
//wait 隻是等待異步任務結束,不會重置目前std::future,是以還是valid
if(ret.valid()){
std::cout << "valid" << std::endl;
}else{
std::cout << "invalid" << std::endl;
}
std::cout << "----------" << std::endl;
//get 會等待異步任務結束并擷取結果,get會重置 std::future,是以會變成 invalid
int result = ret.get();
if(ret.valid()){
std::cout << "valid" << std::endl;
}else{
std::cout << "invalid" << std::endl;
}
}