首页 > 编程语言 >C++11异步编程(std::async, std::future, std::packaged_task, std::promise)

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

时间:2023-03-12 14:31:33浏览次数:53  
标签:std 11 task get packaged future 线程 promise


文章目录

  • ​​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)_c++_02


标签:std,11,task,get,packaged,future,线程,promise
From: https://blog.51cto.com/u_12740336/6115853

相关文章

  • 【题解】CF1801G A task for substrings
    考虑拆开贡献,前缀贡献痕容易算。而跨越\([l-1,l]\)的贡献,考虑在正串ACAM找到\([1,l-1]\),反串ACAM找到\([l,r]\),那么要做的就是在两串的fail链祖先上,找到能凑成完......
  • Day11-综合案例
    1.面向接口的开发(spring的ioc)掌握1.问题我们之前在servlet中创建业务层对象:UserServiceImplservice=newUserServiceImpl();UserServiceImpl属于一个类弊端:如......
  • P1149 [NOIP2008 提高组] 火柴棒等式 题解
    [NOIP2008提高组]火柴棒等式题目描述给你\(n\)根火柴棍,你可以拼出多少个形如\(A+B=C\)的等式?等式中的\(A\)、\(B\)、\(C\)是用火柴棍拼出的整数(若该数非零,则最高......
  • P1102 A-B 数对
    题目链接:https://www.luogu.com.cn/problem/P1102方法1:二分答案#include<bits/stdc++.h>usingnamespacestd;intn,c,a[200005];longlongans;intmain(){ cin......
  • P2065 [TJOI2011] 卡片
    桌子上有mm张蓝色卡片与nn张红色卡片,每张卡片上有一个大于1的整数。现在你要从桌子上拿走一些卡片,分若干次拿。每次只能拿走一组卡片:这组卡片颜色不同,并且两张卡片......
  • 每日算法 230311
    题目面试题17.05.字母与数字难度中等153给定一个放有字母和数字的数组,找到最长的子数组,且包含的字母和数字的个数相同。返回该子数组,若存在多个最长子数组,返回左端......
  • day11 (2023.3.11)
    1.String字符串12.String字符串2 运行结果: 3.内部类 测试类和运行结果: 4.静态内部类和运行结果: 5.匿名内部类和局部内部类 面向对象基本完结。da......
  • day11
    包机制packagecom.xiao.operator;importcom.xiao.base.*//*导入所有类importjava.util.Date;publicclassDemo05{publicstaticvoidmain(String[]......
  • [oeasy]python0105_七段数码管_7_SEGMENT_数码管驱动_4511
    七位数码管回忆上次内容上次回顾了指示灯辉光管 并了解了驱动(driver)驱动就是控制设备工作的人(模块)  辉光管离我们的......
  • 2023/3/11 考试总结
    时间安排7.30~8.00询问很复杂,但是数据随机。直觉告诉我,直接暴力就是对的。写了个set把每个区间存在它的最大值和最小值位置上,然后暴力修改,但是大样例跑了很久。8.00~9......