文章目录

  • ​​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;
}

C++11异步编程(std::async, std::future, std::packaged_task, std::promise)_c++

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)_异步操作_02