本节讨论c++11中std::packaged_task的特性与使用方法

std::packaged_task<>
std::packaged_task<>是一个类模板,代表一个异步任务。封装了
1、可调用实体,即函数,lambda函数或函数对象
2、一个共享状态,通过关联的回调来存储返回的值或抛出的异常。

//从DB获取数据
std::string gtDataFromDB(std::string token){//Do some stuff to fetch the datastd::string data = "Data fetched from DB by filter :: + token;return data;
}

现在我们想在一个单独的线程中执行该函数,但是我们如果在其他线程结束的情况下在主线程中获取结果或异常返回?
一种方法是更改函数声明并在函数中传递std::promise。在传递线程函数中的std::promise<>对象之前,将相关的std::future<>从中取出并保存在主线程中。现在,在线程函数返回其值之前,应该在传入的std::promise参数中设置它,所以它可以在主线程的相关std::future对象中使用。参考第八节
******************************************

但是,如果我们使用std::packaged_task<>,则可以避免创建std::promise和更改函数代码。

使用packaged_task<>创建异步任务
std::packaged_task<>可以包装一个标准函数,使其适用于作为异步功能运行。
当std::packaged_task<>在一个单独的线程中运行时,它会调用相关的回调函数,并将返回值或异常存储在其内部共享状态中。该值可以通过std :: future <>对象在其他线程或主函数中访问。

从上面提到的函数创建一个packaged_task<>,运行于独立的线程并从其future<>对象获取返回值。创建std::packaged_task<> 对象
std::packaged_task<>对象是一个类模板,因此我们需要将模板参数传递给packaged_task<>,即可调用函数的类型。

//创建封装了回调函数的packaged_task<>
std::packaged_task<std::string(std::string)> task(getDataFromDB);

获取future对象

//从packaged_task<>获取相关future<>
std::future<std::string> result = task.get_future();

传递packaged_task<>给线程

std::packaged_task<>可移动,但是不可复制,所以我们需要将它传递给线程

//传递packaged_task<>给线程以异步运行
std::thread th(std::move(task), "Arg");

由于packaged_task只可以移动,不可以复制,因此我们在将它移动到线程之前从它那里取出了 std::future<>对象。
线程将会执行这个任务,该任务在内部调用相关的可调用实体,例如我们的函数getDataFromDB()。
当这个函数给出返回值时,std::packaged_task<>将其设置为关联的共享状态,getDataFromDB()返回的结果或异常最终会在关联的未来对象中可用。

//获取packaged_task<>返回的结果,即getDataFromDB()返回的值。
std::string data = result.get();

get()函数将会阻塞调用线程,直到有可调用的实体返回,并且std::packaged_task<>将数据设置为其可共享的状态。

完整的例子如下:

#include <iostream>
#include <thread>
#include <future>
#include <string>//从DB获取数据
std::string getDataFromDB(std::string token) {//获取数据std::string data = "Data fetched from DB by Filter :: " + token;return data;
}int main() {//创建封装回调函数的packaged_task<>std::packaged_task<std::string(std::string)> task(getDataFromDB);//从packaged_task<>获取相关的future<>std::future<std::string> result = task.get_future();//将packaged_task传递给线程以异步运行std::thread th(std::move(task), "Arg");//join线程,阻塞直到线程完成时返回th.join();//获取packaged_task<>的结果,即getDataFromDB()的返回值std::string data = result.get();std::cout << data << std::endl;return 0;
}

输出:

Data fetched from DB by Filter :: Arg

我们可以在同一行,用lambda函数或函数对象创建一个packaged_task

使用lambda函数创建packaged_task

#include <iostream>
#include <thread>
#include <future>
#include <string>int main() {//创建封装了lambda函数的packaged_task<>std::packaged_task<std::string(std::string)> task([](std::string token) {std::string data = "Data From " + token;return data;});//从packaged_task<>获取相关的future<>std::future<std::string> result = task.get_future();//将packaged_task传递给线程以异步运行std::thread th(std::move(task), "Arg");//join线程,阻塞直到线程完成时返回th.join();//获取packaged_task<>的结果,即getDataFromDB()的返回值std::string data = result.get();std::cout << data << std::endl;return 0;
}

输出:

Data fetched from DB by Filter :: Arg

使用函数对象创建packaged_task

#include <iostream>
#include <thread>
#include <future>
#include <string>//从DB获取数据的函数对象
struct DBDataFetcher {std::string operator ()(std::string token) {std::string data = "Data From " + token;return data;}
};int main() {//使用函数对象创建packaged_taskstd::packaged_task<std::string(std::string)> task(std::move(DBDataFetcher()));//从packaged_task<>获取相关的future<>std::future<std::string> result = task.get_future();//将packaged_task传递给线程以异步运行std::thread th(std::move(task), "Arg");//join线程,阻塞直到线程完成时返回th.join();//获取packaged_task<>的结果,即getDataFromDB()的返回值std::string data = result.get();std::cout << data << std::endl;return 0;
}

输出:

Data fetched from DB by Filter :: Arg

原文链接:https://blog.csdn.net/lijinqi1987/article/details/78909524

c++11多线程之packaged_task<>介绍与实例相关推荐

  1. C++11多线程之future和promise

    std::future和promise的作用是在不同线程之间传递数据.使用指针也可以完成数据的传递,但是指针非常危险,因为互斥量不能阻止指针的访问:而且指针的方式传递的数据是固定的,如果更改数据类型, ...

  2. c++11多线程编程(十):packaged_task介绍与实例

    本节讨论c++11中std::packaged_task的特性与使用方法 std::packaged_task<> std::packaged_task<>是一个类模板,代表一 ...

  3. C++ 11 多线程之future

    什么是std::future? 在C++ 11中std::future是一个绕不开的新特性,因为他的引入极大提高了大家编码的效率.std::future是一个类模板,它将存放着一个未来的变量,而这个变 ...

  4. c++多线程之packaged_task

    packaged_task是个类模板,用于打包任务,把任务包装起来.它的模板参数是各种调用对象,通过std::packaged_task来把各种可调用对象包装起来,方便将来作为线程入口函数来调用.下面 ...

  5. C++11 并发指南四(future 详解二 std::packaged_task 介绍)

    上一讲<C++11 并发指南四(<future> 详解一 std::promise 介绍)>主要介绍了 <future> 头文件中的 std::promise 类, ...

  6. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  7. 异步多线程之ThreadPool详解

    上一篇:异步多线程之Thread 下一篇:异步多线程之入Task 介绍 ThreadPool 是 .net 2.0 时代的产物,有了 Thread 为什么还会有 ThreadPool 呢?Thread ...

  8. Asp.Net Core 轻松学-多线程之Task快速上手

    Asp.Net Core 轻松学-多线程之Task快速上手 原文:Asp.Net Core 轻松学-多线程之Task快速上手 前言     Task是从 .NET Framework 4 开始引入的一 ...

  9. 学计算机的学校17w,摇号中签率23.19%,学费一年17W?11所民校详情介绍!

    原标题:摇号中签率23.19%,学费一年17W?11所民校详情介绍! 民校专辑 点击蓝色字体查看学校具体介绍 2021小升初已经进入准备阶段,家长帮一路跟进小升初进度,帮助家长朋友搜集一手咨询,掌握最 ...

最新文章

  1. 一块CPU就能运行超逼真水流特效!胡渊鸣的算法被这样实现,本人看了都说好...
  2. 微众WeCross 跨链平台(7)跨链路由
  3. Spark-1.4.0集群搭建
  4. ImageNet验证集6%的标签都是错的,MIT:十大常用数据集没那么靠谱
  5. Android Sdk 安装配置
  6. 在shell中获取当前机器的ip地址
  7. Safe handle has been closed异常的原因及解决思路
  8. 分支限界法解决01背包问题
  9. mpvue返回上一个页面_服务器出现404页面是什么情况了
  10. qt 右键显示设置界面 后台运行_1.1安装Qt
  11. 自底向上和自顶向下的区别
  12. HIS(Hospital Information System,医院信息系统)简介
  13. ShadowGun代码
  14. 人脸识别ROC曲线绘制1--生成人脸feature文本
  15. 计算机更换内存条后无法连接网络,换主机后怎么连接网络
  16. Unity Realistic FPS插件 Ironsights脚本简化
  17. 学习前端常用到的网站
  18. linux bochs 网络,Linux下Bochs的使用(转载)
  19. 认识Hive,以及Hive的数据定义与数据操作,hive的数据查询和hive函数
  20. 以太网 VLAN数据帧格式、交换机接口类型介绍、u和t的区别和作用

热门文章

  1. 计算机发展最新趋势素材,计算机方面论文范文素材,与关于计算机科学与技术的趋势探究相关论文网...
  2. mysql 更新索引_MySQL索引优化
  3. Verilog hdl与VHDL混用详解
  4. frontpage编辑html,怎样用FrontPage软件编辑HTML帖子 | 音画代码学堂 - 中国音画家园 - Po...****...
  5. 3d 根据弧长算角度_三分钟带你了解三姆森3D玻璃厚度及轮廓度检测
  6. php的验证码要gd库,PHP利用GD库实现一个简单的验证码
  7. linux如何移动数据到文件系统,怎么把数据文件从文件系统移动到asm?
  8. Java程序中AB类可调用_19年【石油大学】《Java语言程序设计》二次在线作业(100分)...
  9. mysql schema table_关于数据库中table与schema的区别详解
  10. word文档打印 自动编码_职场老油条才知道的3个Word打印技巧,一年能节省几百张打印纸!...