文章目录

  • 描述
  • 函数成员及使用
  • 总结

我们上一篇描述关于C++多线程中的异步操作相关库( asyncpromise),本节将分享c++标准库中最后一个多线程异步操作库 package_task的学习笔记。

描述

  • 头文件 <future>

  • 声明方式: template< class R, class ...Args > class packaged_task<R(Args...)>;

  • 简介
    package_task标准类模版包装了任何可调用的目标,其中包括函数,std::bind表达式,lamda表达式或者其他函数对象。并支持package_task对象调用者的异步调用。调用之后的返回值或者产生的异常能够被存储在能够被std::future对象访问的共享状态中。

    综上描述,我们很明显能够体会到该模版类提供的功能和promise类非常接近,但是promise类没有办法初始化所有可调用的对象,promise类仅提供共享状态的多种访问机制并提供线程之间变量的共享机制。

函数成员及使用

  • 构造函数
    packaged_task() noexcept;构造无任务且无共享状态的package_task对象
    template <class F> explicit packaged_task( F&& f ) 构造拥有共享状态和任务副本的 std::packaged_task 对象,
    packaged_task( const packaged_task& ) = delete;复制构造函数被删除, std::packaged_task 仅可移动
    packaged_task( packaged_task&& rhs ) noexcept; rhs 之前所占有的共享状态和任务构造 std::packaged_task ,令 rhs 留在无共享状态且拥有被移动后的任务的状态
    查看如下代码:

    #include <future>
    #include <iostream>
    #include <thread>int fib(int n)
    {if (n < 3) return 1;else {std::cout << "fib  result " << (n-1)+(n-2) << std::endl;return (n-1) + (n-2);}
    }int main()
    {std::packaged_task<int(int)> fib_task(&fib); std::cout << "starting task\n";//此时已经将package_task调用对象的执行返回值转交给future对象,所以后续//的线程执行由惰性赋值来触发。即当future的对象的共享状态尝试获取线程执行//结果的时候才进行线程执行,并返回结果。类似std::async的policy:std::launch::deferredauto result = fib_task.get_future(); std::thread t(std::move(fib_task), 40);std::cout << "waiting for task to finish...\n";std::cout << result.get() << '\n';std::cout << "task complete\n";t.join();
    }
    

    输出如下:

    starting task
    waiting for task to finish...
    fib  result 77
    77
    task complete
    
  • 析构函数~packaged_task()
    抛弃共享状态并销毁存储的任务对象,同 std::promise::~promise ,若在令共享状态就绪前抛弃它,则存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 异常

  • 赋值运算符
    packaged_task& operator=( const packaged_task& ) = delete
    复制赋值运算符被删除, std::packaged_task 仅可移动

  • std::packaged_task<R(Args...)>::get_future返回与 *this 共享同一共享状态的 future
    promise类一样,get_future 只能对每个 packaged_task 调用一次
    get_future成员出现异常的情况如下:

    • 已通过调用 get_future 取得共享状态。设置 error_category 为 future_already_retrieved
    • *this 无共享状态。设置 error_category 为 no_state
  • std::packaged_task<R(Args...)>::make_ready_at_thread_exit成员函数
    以转发的 args 为参数调用存储的任务。任务返回值或任何抛出的异常被存储于 *this 的共享状态。

    仅在当前线程退出,并销毁所有线程局域存储期对象后,才令共享状态就绪
    代码如下

    #include <future>
    #include <iostream>
    #include <chrono>
    #include <thread>
    #include <functional>
    #include <utility>void worker(std::future<void>& output)
    {std::packaged_task<void(bool&)> my_task{ [](bool& done) { done=true; } };auto result = my_task.get_future();bool done = false;//根据打印已经可以看到,此时已经执行了package_task的线程内容//但是共享状态到函数作用域结束之前并未就绪my_task.make_ready_at_thread_exit(done); // 立即执行任务std::cout << "worker: done = " << std::boolalpha << done << std::endl;auto status = result.wait_for(std::chrono::seconds(0));if (status == std::future_status::timeout)std::cout << "worker: result is not ready yet" << std::endl;output = std::move(result);
    }int main()
    {std::future<void> result;std::thread{worker, std::ref(result)}.join();//等到线程函数返回结果,且future对象就绪之后,可以看到打印状态变为就绪auto status = result.wait_for(std::chrono::seconds(0));if (status == std::future_status::ready)std::cout << "main: result is ready" << std::endl;
    }
    

总结

综上对package_task的描述,我们可以看到package_task模版类就像promise一样可以被异步调用,并且将调用对象执行的结果封装在future的共享状态中,来让调用者获取。同时package_task的调用者获取调用对象的执行结果过程就像async的惰性求值策略,当调用者想要获取调用对象的执行结果时才开始执行调用对象。

package_task的优势更多是它能够初始化所有的可调用对象,并且支持对该调用对象的异步访问机制。
promise更多的优势是线程之间的变量的传递,同时返回future类的共享状态。同时它也能够支持多种共享状态的访问机制,惰性求值/立即执行。

所以C++多线程的几个异步操作promiseasyncpackage_task都可以进行线程之间的异步操作,希望以此笔记在今后多线程编程中各持所需进行学习。

C++多线程:package_task异步调用任何目标执行操作相关推荐

  1. springboot 多线程_SpringBoot异步调用@Async

    一. 什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行. 二. 如何实现异步调用 ...

  2. 衔接UI线程和管理后台工作线程的类(多线程、异步调用)[转]

    一.引言      在编写Windows form时,如果直接在UI线程要运行一个费时方法的话(如从数据库查询大量数据时),会引起程序"假死",从而导致用户不满.这个时候就需要通过 ...

  3. Java多线程实现异步调用

    在Java平台,实现异步调用的角色有如下三个角色:调用者. 提货单 .真实数据,一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单 .然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买 ...

  4. Spring Boot 中使用@Async实现异步调用,加速任务执行!

    欢迎关注方志朋的博客,回复"666"获面试宝典 什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照 ...

  5. 关于.NET异步调用的初步总结

    最近看了看.NET异步调用方面的资料,现择重点总结,若有纰漏敬请指正. 异步调用的实质: 异步调用通过委托将所需调用的方法置于一个新线程上运行,从而能够使一个可能需要较长时间的任务在后台执行而不影响调 ...

  6. SpringBoot异步调用

    2.1.无返回值的异步方法 2.1.有返回值的异步方法 3.1.方法级别重写Executor 3.2.应用级别重写Executor 3.3.自定义线程池配置 "异步调用"对应的是& ...

  7. 如何从异步调用返回响应?

    我有一个函数foo ,它发出Ajax请求. 如何返回foo的响应? 我尝试从success回调中返回值,以及将响应分配给函数内部的局部变量并返回该局部变量,但这些方法均未真正返回响应. functio ...

  8. C#的同步和异步调用方法

    同步和异步大家都明白什么意思,在这里不多介绍了. namespace ConsoleTest {class Program{static void Main(string[] args){Consol ...

  9. Spring Boot中使用@Async实现异步调用

    什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执 ...

最新文章

  1. 机器学习与高维信息检索 - Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及基于CVXOPT的相关实例
  2. 【深度学习】深入理解Batch Normalization批标准化
  3. 使用JDK自带的工具jstack找出造成运行程序死锁的原因
  4. Jenkins Robot framework 持续集成环境搭建
  5. 均匀B样条和准均匀B样条
  6. 导入自己写好的python包
  7. 51单片机学习笔记003-----烧录软件和编译器的安装
  8. 口袋妖怪lets go服务器维护中,口袋妖怪lets go攻略 口袋妖怪lets go新手攻略(中)...
  9. 大业达公司裁员风云2
  10. 在ubuntu中添加widows启动项的简单方法
  11. 2015境外人气餐厅榜单!你吃过几家?
  12. idea创建分支、合并分支、解决分支冲突
  13. MIPI CSI和DSI接口标准简介
  14. 2018-2021,60+篇阿里研发效能提升合集,都在这里了
  15. selenium入门超详细教程——网页自动化操作
  16. 快手2020校园招聘秋招笔试--工程C试卷 (编程题题解全)
  17. python 网络爬虫(慕课网)
  18. 微软为阻止恶意软件侵害禁用Excel4.0宏、开源网站插件存在上万个安全漏洞|1月24日全球网络安全热点
  19. 迁移prometheus数据
  20. 计算机网络 互联网的路由选择协议——OSPF

热门文章

  1. js便利关联数组 及数组定义方式 分类
  2. JS中window.event事件使用详解
  3. C#关于面对象多态例子
  4. java 编码过滤器_Java编码过滤器
  5. 编写程序实验两个数的加减结果的判断_力学实验1:实验基础与实验仪器
  6. 规则管理_看板管理的五大使用规则
  7. 字符串数组(就自己做个笔记)
  8. 给模型加装饰器Java,装饰器设计模式
  9. java类引用接口的注释_java – 在接口类型上使用注释有什么好处?
  10. java格林认证_Java考试格林模拟题