文章目录
- 1.std::future概述含义
- 2.std::future
- 2.std::packaged_task
- 2.std::promise
1.std::future概述含义
C++0x提供了future和promise来简化任务线程间的返回值操作;
- 同时为启动任务线程提供了packaged_task以方便操作。其中的关键点是允许2个任务间使用无(显式)锁的方式进行值传递;标准库帮你高效的做好这些了。
- 基本思路很简单:当一个任务需要向父线程(启动它的线程)返回值时,它把这个值放到promise中。
- 之后,这个返回值会出现在和此promise关联的future中。
- 于是父线程就能读到返回值。
- 更简单点的方法,参看async()。
std::async是一个函数模板,会启动一个异步任务,最终返回一个std::future对象。
- 在之前是通过thread去创建一个子线程,但是如果我们要得到这个子线程所返回的结果,那么可能就需要用全局变量或者引用的方法来得到结果,这样或多或少都会不太方便。
- 那么async这个函数就可以将得到的结果保存在future中,然后通过future来获取想要得到的结果。
- async比起thread来说可以对线程的创建又有了更好的控制,比如可以延迟创建。
2.std::future
标准库中提供了3种future:
- 普通future
- 复杂场合使用的shared_future和
- atomic_future。
- future最主要的目的还是提供一个简单的获取返回值的方法:get()。
- eg:只展示了普通future,它已经完全够用了。如果我们有一个future f,通过get()可以获得它的值:
X v = f.get(); // if necessary wait for the value to get computed
如果它的返回值还没有到达,调用线程会进行阻塞等待。
等待超时,get()会抛出异常的(从标准库或等待的线程那个线程中抛出)
如果我们不需要等待返回值(非阻塞方式),可以简单询问一下future,看返回值是否已经到达:
if (f.wait_for(0))
{
// there is a value to get()
// do something
}
else
{
// do something else
}
- std::future是一个类模板,提供了一个访问异步操作的结果的机制。
- 我们可以通过future_status去查询future的三种状态,分别是deferred(还未执行),ready(已经完成),timeout(执行超时),所以我们可以通过这个去查询异步操作的状态。- future提供了一些函数比如get(),wait(),wait_for(),
(1)一般用get()来获取future所得到的结果,如果异步操作还没有结束,那么会在此等待异步操作的结束,并获取返回的结果;
(2)wait()只是在此等待异步操作的结束,并不能获得返回结果。
(3)wait_for()超时等待返回结果。
// future<获取的结果类型> 变量名
// async(函数名, 参数)
std::future<int> fu = std::async(fun, 1);
std::cout << fu.get() << std::endl;
2.std::packaged_task
std::packaged_task是一个类模板,顾名思义是用来打包的,将一个可调用对象封装起来,然后可以将其的返回值传给future。
std::packaged_task<函数返回类型(参数类型)> 变量名(函数名)。
- 下面展示一下std::packaged_task()的简单用法,也可以将函数换成lambda表达式。
#include <iostream>
#include <future>
#include <thread>
int fun(int x) {
x++;
x *= 10;
std::cout << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
return x;
}
int main()
{
std::packaged_task<int(int)> pt(fun); // 将函数打包起来
std::future<int> fu = pt.get_future(); // 并将结果返回给future
std::thread t(std::ref(pt), 1);
std::cout << fu.get() << std::endl;
std::cout << std::this_thread::get_id() << std::endl;
t.join();
return 0;
}
2.std::promise
promise的主要目的是提供一个”put”(或”get”,随你)操作,以和future的get()对应。
- promise为future传递的结果类型有2种:传一个普通值或者抛出一个异常
try {
X res;
// compute a value for res
p.set_value(res);
}
catch (…) { // oops: couldn’t compute res
p.set_exception(std::current_exception());
}
- 最普遍的情况是父子线程配对形式,父线程用future获取子线程promise返回的值。
- packaged_task提供了启动任务线程的简单方法。
特别是它处理好了future和promise的关联关系,同时提供了包装代码以保证返回值/异常可以放到promise中,示例代码:
void comp(vector& v)
{
// package the tasks:
// (the task here is the standard
// accumulate() for an array of doubles):
packaged_task pt0{std::accumulate};
packaged_task pt1{std::accumulate};
auto f0 = pt0.get_future(); // get hold of the futures
auto f1 = pt1.get_future();
pt0(&v[0],&v[v.size()/2],0); // start the threads
pt1(&[v.size()/2],&v[size()],0);
return f0.get()+f1.get(); // get the results
}
- std::promise是一个类模板,它的作用是在不同的线程中实现数据的同步,与future结合使用,也间接实现了future在不同线程间的同步。
- promise中set_value_at_thread_exit()的含义如下:
直到它的作用是当在这个线程执行结束的时候才会将future的状态设置为ready,而set_value()则直接将future的状态设置为ready。
需要注意的是在使用的过程中不能多次set_value(),也不能多次get_future()和多次get(),因为一个promise对象只能和一个对象相关联,否则就会抛出异常。
#include <iostream>
#include <future>
#include <thread>
int fun(int x, std::promise<int>& p) {
x++;
x *= 10;
p.set_value(x);
std::cout << std::this_thread::get_id() << std::endl;
return x;
}
int main()
{
std::promise<int> p;
std::future<int> fu = p.get_future(); // 并将结果返回给future
std::thread t(fun, 1, std::ref(p));
std::cout << fu.get() << std::endl; // 当promise还没有值的时候在此等待
std::cout << std::this_thread::get_id() << std::endl;
t.join();
return 0;
}
- 参考:C++11异步编程(std::async, std::future, std::packaged_task, std::promise),std::future和std::promise