当前位置:   article > 正文

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

c++ 异步编程

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       
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 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;
  • 1
  • 2
  • 3
  • 4

2.std::packaged_task

std::packaged_task是一个类模板,顾名思义是用来打包的,将一个可调用对象封装起来,然后可以将其的返回值传给future。

std::packaged_task<函数返回类型(参数类型)> 变量名(函数名)
  • 1
  • 下面展示一下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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

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());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 最普遍的情况是父子线程配对形式,父线程用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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/922395
推荐阅读
相关标签
  

闽ICP备14008679号