C++11之std::future和std::promise和std::std::packaged_task
为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执行join(),过程相对繁琐。
thread库提供了future用来访问异步操作的结果。std::promise用来包装一个值将数据和future绑定起来,为获取线程函数中的某个值提供便利,取值是间接通过promise内部提供的future来获取的,也就是说promise的层次比future高。

#include "stdafx.h"
#include <iostream>
#include <type_traits>
#include <future>
#include <thread> using namespace std;
int main()
{
std::promise<int> promiseParam;
std::thread t([](std::promise<int>& p)
{
std::this_thread::sleep_for(std::chrono::seconds(10));// 线程睡眠10s
p.set_value_at_thread_exit(4);//
}, std::ref(promiseParam));
std::future<int> futureParam = promiseParam.get_future(); auto r = futureParam.get();// 线程外阻塞等待
std::cout << r << std::endl; return 0;
}

上述程序执行到futureParam.get()时,有两个线程,新开的线程正在睡眠10s,而主线程正在等待新开线程的退出值,这个操作是阻塞的,也就是说std::future和std::promise某种程度也可以做为线程同步来使用。
std::packaged_task包装一个可调用对象的包装类(如function,lambda表达式(C++11之lambda表达式),将函数与future绑定起来。std::packaged_task与std::promise都有get_future()接口,但是std::packaged_task包装的是一个异步操作,而std::promise包装的是一个值。

#include "stdafx.h"
#include <iostream>
#include <type_traits>
#include <future>
#include <thread> using namespace std;
int main()
{
std::packaged_task<int()> task([]() {
std::this_thread::sleep_for(std::chrono::seconds(10));// 线程睡眠10s
return 4; });
std::thread t1(std::ref(task));
std::future<int> f1 = task.get_future(); auto r = f1.get();// 线程外阻塞等待
std::cout << r << std::endl; return 0;
}

std::future
std::future是一个非常有用也很有意思的东西,简单说std::future提供了一种访问异步操作结果的机制。从字面意思来理解,它表示未来,我觉得这个名字非常贴切,因为一个异步操作我们是不可能马上就获取操作结果的,只能在未来某个时候获取,但是我们可以以同步等待的方式来获取结果,可以通过查询future的状态(future_status)来获取异步操作的结果。future_status有三种状态:
- deferred:异步操作还没开始
- ready:异步操作已经完成
- timeout:异步操作超时

//查询future的状态
std::future_status status;
do {
status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::deferred) {
std::cout << "deferred\n";
} else if (status == std::future_status::timeout) {
std::cout << "timeout\n";
} else if (status == std::future_status::ready) {
std::cout << "ready!\n";
}
} while (status != std::future_status::ready);

获取future结果有三种方式:get、wait、wait_for,其中get等待异步操作结束并返回结果,wait只是等待异步操作完成,没有返回值,wait_for是超时等待返回结果。
std::promise
std::promise为获取线程函数中的某个值提供便利,在线程函数中给外面传进来的promise赋值,当线程函数执行完成之后就可以通过promis获取该值了,值得注意的是取值是间接的通过promise内部提供的future来获取的。它的基本用法:
std::promise<int> pr;
std::thread t([](std::promise<int>& p){ p.set_value_at_thread_exit(9); },std::ref(pr));
std::future<int> f = pr.get_future();
auto r = f.get();
std::packaged_task
std::packaged_task它包装了一个可调用的目标(如function, lambda expression, bind expression, or another function object),以便异步调用,它和promise在某种程度上有点像,promise保存了一个共享状态的值,而packaged_task保存的是一个函数。它的基本用法:
#include <chrono>
#include <functional>
int Test_Fun(int a, int b, int &c)
{
//a=1,b=2,c=0
//突出效果,休眠5s
std::this_thread::sleep_for(std::chrono::seconds(5));
//c=233
c = a + b + 230;
return c;
}
int main()
{
//声明一个std::packaged_task对象pt1,包装函数Test_Fun
std::packaged_task<int(int, int, int&)> pt1(Test_Fun);
//声明一个std::future对象fu1,包装Test_Fun的返回结果类型,并与pt1关联
std::future<int> fu1 = pt1.get_future();
//声明一个变量
int c = 0;
//创建一个线程t1,将pt1及对应的参数放到线程里面执行
std::thread t1(std::move(pt1), 1, 2, std::ref(c)); //这必须用转移,或std::ref(pt1)
t1.join();
//阻塞至线程t1结束(函数Test_Fun返回结果)
int iResult = fu1.get();
std::cout << "执行结果:" << iResult << std::endl; //执行结果:233
std::cout << "c:" << c << std::endl; //c:233
system("pause");
return 1;
}
而std::async比std::promise, std::packaged_task和std::thread更高一层,它可以直接用来创建异步的task,异步任务返回的结果也保存在future中。std::async的原型:
async( std::launch policy, Function&& f, Args&&... args );
std::launch policy有两个,一个是调用即创建线程(std::launch::async),一个是延迟加载方式创建线程(std::launch::deferred),当掉使用async时不创建线程,知道调用了future的get或者wait时才创建线程。之后是线程函数和线程参数。

#include "stdafx.h"
#include <iostream>
#include <future>
#include <thread> int main()
{
// future from a packaged_task
std::packaged_task<int()> task([]() {
std::cout << "packaged_task started" << std::endl;
return 7; }); // wrap the function
std::future<int> f1 = task.get_future(); // get a future
std::thread(std::move(task)).detach(); // launch on a thread // future from an async()
std::future<int> f2 = std::async(std::launch::deferred, []() {
std::cout << "Async task started" << std::endl;
return 8; }); // future from a promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread([&p] { p.set_value_at_thread_exit(9); }).detach(); f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: "
<< f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}
C++11之std::future和std::promise和std::std::packaged_task的更多相关文章
- C++11 并发指南四(<future> 详解三 std::future & std::shared_future)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- C++11 并发指南四(<future> 详解三 std::future & std::shared_future)(转)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- C++ 11新特性:std::future & std::shared_future) (转载)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- 【C++并发实战】(三) std::future和std::promise
std::future和std::promise std::future std::future期待一个返回,从一个异步调用的角度来说,future更像是执行函数的返回值,C++标准库使用std::f ...
- C++11之std::future和std::promise
为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执 ...
- C++并发编程之std::async(), std::future, std::promise, std::packaged_task
c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...
- C++11 使用异步编程std::async和std::future
先说明一点:std::asyanc是std::future的高级封装, 一般我们不会直接使用std::futrue,而是使用对std::future的高级封装std::async. 下面分别说一下. ...
- C++并发编程之std::future
简单地说,std::future 可以用来获取异步任务的结果,因此可以把它当成一种简单的线程间同步的手段.std::future 通常由某个 Provider 创建,你可以把 Provider 想象成 ...
- 第27课 “共享状态”及其管理者(std::future/std::shared_future)
一. “共享状态” (一)“共享状态”对象 1. 用于保存线程函数及其参数.返回值以及新线程状态等信息.该对象通常创建在堆上,由std::async.std::promise和std::package ...
随机推荐
- Node.js frameworks
1. Express 2. Koa 3. LoopBack egghead.io What is egghead? egghead is a group of working web developm ...
- 完全原生javascript简约日历插件,js、html
效果图: 效果如图所示,尽管看上去并不是很美观,但是,基本上的功能还是已经完成了,码了一天多的时间,权当做复习一下js吧. 整个做下来差不多码了500多行代码~其实只是很多的样式也包括了在其中了,虽然 ...
- linux输出之 printf 讲解--->与 echo 的区别
printf 你接触过printf没呢?? 如果你学了c语言的话你肯定就熟悉了,如果没有的话,不要急,,我保证你马上就会了! 我们来看一下案例: 这个可以看出来吧,echo输出的话会对文本换行哦,但是 ...
- (转)DB2中的一些函数
DB2中的一些函数 原文:https://www.cnblogs.com/ShaYeBlog/archive/2012/08/27/2658025.html 最近用DB2,数据库之间的差异还是很大的, ...
- spring-data-elasticsearch使用笔记
使用spring-data遇到了一些问题,记录一下. spring-data-elasticsearch版本选择 这里有一份官方github上的spring-data-elasticsearch与el ...
- vi编辑器备忘录
1. 基本操作 G 移动到文件最后一行 nG 移动到n行 gg 移动到第一行 N[Enter] 向下移动n行 /word 向下寻找 ?word 向上寻找 n 查找下一个 N 查找上一个 0或者Home ...
- C#的params参数遇到null
params参数支持数组作为参数传入,但并不支持List 定义一个使用params的参数 private static void UseParam(params int[] args) { if (a ...
- pulic——function(下载的公共的)
1. /* * 用途: 对Date的扩展,将 Date 转化为指定格式的String */ // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年( ...
- mysql 查询及 删除表中重复数据
CREATE TABLE `test` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) NULL DEFAULT NULL, `a ...
- bzoj 4574: [Zjoi2016]线段树
Description 小Yuuka遇到了一个题目:有一个序列a_1,a_2,?,a_n,q次操作,每次把一个区间内的数改成区间内的最大值,问 最后每个数是多少.小Yuuka很快地就使用了线段树解决了 ...