什么是std::future?
在C++ 11中std::future是一个绕不开的新特性,因为他的引入极大提高了大家编码的效率。std::future是一个类模板,它将存放着一个未来的变量,而这个变量可以通过std::future提供的成员函数std::future::get()来得到。
std::future从何而来?
std::future通常可以通过调用函数(provider)来构造对象,provider一般指std::async、std::promise、std::packaged_task
- std::async 函数
- std::promise::get_future:get_future 为 promise 类的成员函数
- std::packaged_task::get_future: get_future为 packaged_task 的成员函数
如果std::future这个变量尚未被赋值之前,就有其他线程试图通过std::future::get()获取这个变量,那么这个调用std::future::get()线程将会被阻塞到这个变量可以获取为止,才会继续执行。
std::future的构成
-
基础函数(构造、析构、赋值):
std::future 的拷贝构造函数是被禁用的,只提供了默认的构造函数和移动构造函数。另外,std::future的赋值构造函数禁用,只提供了 move 赋值操作 -
share函数:获取共享的future,返回一个std::shared_future对象,该对象获取future对象的共享状态。future对象将不再有效。
-
valid函数:检查共享状态的有效性,返回当前的future对象是否与共享状态关联。一旦调用了std::future::get()函数,再调用此函数将返回false。
-
wait函数:等待共享状态就绪,如果共享状态尚未就绪(即提供者尚未设置其值或异常),则该函数将阻塞调用者的线程直至共享状态就绪后,该函数将取消阻塞并void返回。
-
wait_for函数:等待共享状态在指定的时间内(时间片)准备就绪,如果同样尚未就绪,则该函数将阻塞调用者的线程直到就绪或已达到设置超时的时间。
此函数的返回值类型为枚举类future_status。- ready:共享状态已就绪或者异常;
- timeout:在规定的时间内未就绪;
- deferred:异步函数操作还没开始;
-
wait_until函数:等待共享状态在指定的时间点(时间点)准备就绪,如果同样尚未就绪,则该函数将阻塞调用者的线程直到就绪或已达到设置超时的时间。
此函数的返回值类型为枚举类future_status,具体释义同上
代码释义
#include <future>
#include <iostream>
#include <chrono>
using namespace std;
namespace {
int TestFunc(int x)
{
cout << "thread id=" << std::this_thread::get_id() << endl;
int result = 0;
for (int i = 0; i < x; i++) {
result += 3;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return result;
}
} // namespace
void Test_share()
{
std::future<int> ret_data = std::async([] { return 50; });
std::shared_future<int> shared_ret_data = ret_data.share();
try {
// share()后,ret_data对象将变得无效,调用空指针
std::cout << "ret_data valid: " << ret_data.valid() << endl;
std::cout << "ret_data get: " << ret_data.get() << endl;
} catch (const std::future_error& e) {
// exception: std::future_error
std::cout << "future_error : " << e.what() << std::endl;
}
//std::shared_future对象,get函数可以被多次访问
std::cout << "value: " << shared_ret_data.get() << endl;
std::cout << "its double: " << shared_ret_data.get() * 2 << endl;
}
void Test_valid_get()
{
std::future<int> ret_data = std::async([] { return 50; });
cout << ret_data.valid() << endl;//获取有效性
cout << ret_data.get() << endl; //first get
cout << ret_data.valid() << endl;//获取有效性
try {
std::cout << "ret_data get: " << ret_data.get() << endl; // second get
} catch (const std::future_error& e) {
// exception: std::future_error
std::cout << "future_error : " << e.what() << std::endl;
}
}
void Test_wait()
{
cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
std::future<int> ret_data = std::async(TestFunc, 5);
std::cout << "wait..." << endl;
ret_data.wait();
std::cout << "ready..." << endl;
std::cout << "ret_data get: " << ret_data.get() << endl; // second get
}
void Test_wait_()
{
/*
enum class future_status { // names for timed wait function returns
ready,
timeout,
deferred
};
*/
int call_sum = 0;
while (cin >> call_sum) {
cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
std::future<int> ret_data = std::async(TestFunc, call_sum);
std::cout << "wait start" << endl;
std::chrono::milliseconds span(200);
std::future_status ret_state = ret_data.wait_for(span);//获取状态
//std::future_status ret_state =
// ret_data.wait_until(std::chrono::system_clock::now() + std::chrono::milliseconds(200)); //获取状态,200ms后
std::cout << "wait end state=" << static_cast<int>(ret_state) << endl;
try {
std::cout << "ret_data get: " << ret_data.get() << endl; // second get
} catch (const std::future_error& e) {
// exception: std::future_error
std::cout << "future_error : " << e.what() << std::endl;
}
}
}
int main()
{
Test_share();
cout << "======================================================" << endl;
Test_valid_get();
cout << "======================================================" << endl;
Test_wait();
cout << "======================================================" << endl;
Test_wait_();
cout << "======================================================" << endl;
}
结果
引申std::shared_future
std::shared_future 与std::future接口基本一致。
与std::shared_future关系
- std::shared_future对象可以通过std::future对象进行隐式转换,也可以通过显示调用std::future::share显示转换,在这两种情况下,原来的std::future对象都会无效。
- 当你需要具有std::future的多个有效拷贝时会用到std::shared_future;或者多个使用者使用std::future时也会用到std::shared_future
主要在用法上有区别
- 支持copy(拷贝构造函数,拷贝赋值操作);
- get()是一个const成员函数,返回一个const reference指向“存储于shared state”的值,通过shared_future::get检索的值不会释放共享对象的所有权
- 共享状态(shared state)的生存期至少要持续到与之关联的最后一个对象被销毁为止。