前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11异步编程(std::async, std::future, std::packaged_task, std::promise)

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

作者头像
Ch_Zaqdt
发布2020-02-15 17:34:52
14.6K0
发布2020-02-15 17:34:52
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACM

? ? ? ?std::async是一个函数模板,会启动一个异步任务,最终返回一个std::future对象。在之前我们都是通过thread去创建一个子线程,但是如果我们要得到这个子线程所返回的结果,那么可能就需要用全局变量或者引用的方法来得到结果,这样或多或少都会不太方便,那么async这个函数就可以将得到的结果保存在future中,然后通过future来获取想要得到的结果。async比起thread来说可以对线程的创建又有了更好的控制,比如可以延迟创建。下面先介绍一下std::future, std::packaged_task, std::promise。

std::future

? ? ? ?std::future是一个类模板,提供了一个访问异步操作的结果的机制。我们可以通过future_status去查询future的三种状态,分别是deferred(还未执行),ready(已经完成),timeout(执行超时),所以我们可以通过这个去查询异步操作的状态。future提供了一些函数比如get(),wait(),wait_for(),一般用get()来获取future所得到的结果,如果异步操作还没有结束,那么会在此等待异步操作的结束,并获取返回的结果。wait()只是在此等待异步操作的结束,并不能获得返回结果。wait_for()超时等待返回结果。

代码语言:javascript
复制
// future<获取的结果类型> 变量名
// async(函数名, 参数)
std::future<int> fu = std::async(fun, 1);    
std::cout << fu.get() << std::endl;

std::packaged_task

? ? ? ?std::packaged_task是一个类模板,顾名思义是用来打包的,将一个可调用对象封装起来,然后可以将其的返回值传给future。std::packaged_task<函数返回类型(参数类型)> 变量名(函数名)。下面展示一下std::packaged_task()的简单用法,也可以将函数换成lambda表达式。

代码语言:javascript
复制
#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;
}

std::promise

?std::promise是一个类模板,它的作用是在不同的线程中实现数据的同步,与future结合使用,也间接实现了future在不同线程间的同步。

代码语言:javascript
复制
#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;
}

? ? ? ?promise还有一个函数是set_value_at_thread_exit()这个翻译一下就可以直到它的作用是当在这个线程执行结束的时候才会将future的状态设置为ready,而set_value()则直接将future的状态设置为ready。需要注意的是在使用的过程中不能多次set_value(),也不能多次get_future()和多次get(),因为一个promise对象只能和一个对象相关联,否则就会抛出异常。

std::async

? ? ? ?其实这个函数是对上面的对象的一个整合,async先将可调用对象封装起来,然后将其运行结果返回到promise中,这个过程就是一个面向future的一个过程,最终通过future.get()来得到结果。它的实现方法有两种,一种是std::launch::async,这个是直接创建线程,另一种是std::launch::deferred,这个是延迟创建线程(当遇到future.get或者future.wait的时候才会创建线程),这两个参数是std::async的第一个参数,如果没有使用这个两个参数,也就是第一个参数为空的话,那么第一个参数默认为std::launch::async | std::launch::deferred,这个就不可控了,由操作系统根据当时的运行环境来确定是当前创建线程还是延迟创建线程。那么std::async的第二个参数就是可调用对象的名称,第三个参数就是可调用对象的参数。

代码语言:javascript
复制
#include <iostream>
#include <future>
#include <thread>

int fun(int x) {
	x++;
	x *= 10;
	std::cout << std::this_thread::get_id() << std::endl;
	return x;
}


int main()
{
    // std::launch::deferred 当执行到fu.get才开始创建线程
	std::future<int> fu = std::async(std::launch::deferred, fun, 1);
	std::cout << fu.get() << std::endl;
	std::cout << std::this_thread::get_id() << std::endl;
	return 0;
}
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • std::future
  • std::packaged_task
  • std::promise
  • std::async
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com