描述:
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 一起使用
gcc 2.cpp -pthread -o 2
#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;
}
}
与 std::promise一起使用
todo
与 std::packaged_task?一起使用
todo
|