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

2023-11-02

本节讨论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 data
	std::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_task
  std::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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++11多线程编程(十):packaged_task<>介绍与实例 的相关文章

  • VLC 媒体播放器有 C# 界面吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否可以使用 C 控制台应用程序中的包装器从 VLC 播放中当前播放的文件中读取曲目统计信息 时间 标
  • 使用链表进行堆排序

    我想知道是否有人曾经使用链表进行堆排序 如果他们可以提供代码 我已经能够使用数组进行堆排序 但尝试在链表中进行排序似乎不切实际 而且在你知道的地方很痛苦 我必须为我正在做的项目实现链接列表 任何帮助将不胜感激 我也用C 答案是 你不想在链表
  • 与 for_each 或 std::transform 一起使用时,如何调用 C++ 函子构造函数

    我以前从未使用过 C 函子 所以我只是想了解它们是如何工作的 例如假设我们有这个函子类 class MultiplyBy private int factor public MultiplyBy int x factor x int ope
  • 静态构造函数和 BeforeFieldInit?

    如果类型没有静态构造函数 则将执行字段初始值设定项 就在使用该类型之前 或者在某个时间点突发奇想 运行时 为什么这段代码 void Main start Dump Test EchoAndReturn Hello end Dump clas
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 捕获 .aspx 和 .ascx 页面中的异常

    问题说明了一切 请看以下示例代码 ul li li ul
  • EntityHydrate 任务失败

    我最近安装了 Visual Studio 11 Beta 和 Visual Studio 2010 之后 我无法在 Visual Studio 2010 中构建依赖于 PostSharp 的项目 因此我卸载了 Visual Studio 1
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • Boost ASIO 串行写入十六进制值

    我正在使用 ubuntu 通过串行端口与设备进行通信 所有消息都必须是十六进制值 我已经在 Windows 环境中使用白蚁测试了通信设置 并得到了我期望的响应 但在使用 Boost asio 时我无法得到任何响应 以下是我设置串口的方法 b
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • Makefile 和 .Mak 文件 + CodeBlocks 和 VStudio

    我对整个 makefile 概念有点陌生 所以我对此有一些疑问 我正在 Linux 中使用 CodeBlocks 创建一个项目 我使用一个名为 cbp2mak 的工具从 CodeBlocks 项目创建一个 make 文件 如果有人知道更好的
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • 如何防止 Blazor NavLink 组件的默认导航

    从 Blazor 3 1 Preview 2 开始 应该可以防止默认导航行为 https devblogs microsoft com aspnet asp net core updates in net core 3 1 preview
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 读取依赖步行者输出

    I am having some problems using one of the Dlls in my application and I ran dependency walker on it i am not sure how to
  • 使用 gcc 时在头文件中查找定义的好方法是什么?

    在使用 gcc 时 有人有推荐的方法在头文件中查找定义吗 使用 MSVC 时 我只需右键单击并选择 转到定义 这非常好 我使用过 netbeans gcc 它确实有代码帮助 包括到定义的超链接 所以这是一种选择 但是 我想知道是否有任何其他
  • 调用 .ToArray() 时出现 ArgumentException

    我有一个经常被清除的列表 代码完全是这样的 VisitorAgent toPersist List
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • 声明一个负长度的数组

    当创建负长度数组时 C 中会发生什么 例如 int n 35 int testArray n for int i 0 i lt 10 i testArray i i 1 这段代码将编译 并且启用 Wall 时不会出现警告 并且似乎您可以分配

随机推荐

  • 算法:图解递归算法的应用场景和使用途径

    文章目录 什么是递归 使用递归的原因 如何理解递归 递归的使用写法 典型例题和分析 汉诺塔问题 合并两个有序链表 反转链表 两两交换链表中的节点 pow 总结 什么是递归 递归就是函数自己调用自己的情况 在二叉树 快排 归并中都有较为广泛的
  • LeetCode题目笔记——1604. 警告一小时内使用相同员工卡大于等于三次的人

    文章目录 题目描述 题目难度 中等 方法一 排序 哈希表 代码 Python 代码 C 总结 题目描述 力扣公司的员工都使用员工卡来开办公室的门 每当一个员工使用一次他的员工卡 安保系统会记录下员工的名字和使用时间 如果一个员工在一小时时间
  • microPython在STM32跑一跑

    1 看这个文章在STM32F4 Disco上试用MicroPython MicroPython开源版块 电子工程世界 论坛 于是在DISCOVERY板卡上面代码就能跑起来了 灯可以闪烁 让灯闪烁的代码可以通过串口输入进去 也可以通过通过生成
  • 【TCP/IP】 以太网流量控制------pause流控

    关键字 以太网 数据链路层 PAUSE帧 流量控制 文章目录 关键字 一 以太网的流量控制 二 pause流控的原理和实现 1 pause流控原理 2 pause消息格式 3 pause流控处理逻辑 4 pause流控芯片上的实现 三 pa
  • 网络层设备 —— 路由器

    一 路由器 二 输入端口对线路上收到的分组的处理 三 输出端口将交换结构传送来的分组发送到线路 四 路由表和转发表 1 路由表 根据路由选择算法得出 主要用途是路由选择 其结构需
  • QObject类的对象树机制、qt内存回收机制、deleteLater、 delete与ui关系

    catalog 错误范例 version qt的delete deleteLater机制 deleteLater具体使用 delete与ui关系 错误范例 class MyWidget QWidget QPushButton btn QTa
  • mysql常见面试题

    一 联合索引是什么 为什么需要注意联合索引中的顺序 什么是最左前缀匹配原则 MySQL可以使用多个字段同时建立一个索引 叫做联合索引 在联合索引中 如果想要命中索引 需要按照建立索引时的字段顺序挨个使用 否则无法命中索引 最左前缀匹配原则
  • windows下将tomcat设置为系统服务以便自动启动

    在window sever服务器部署程序的时候 最好是将程序设置为服务 单纯用cmd启动可能会面临被误关掉的风险 写下此日志留作教训 添加为服务 第一步 使用cmd命令进入到tomcat文件下的bin目录 第二步 输入service ins
  • 52 最佳实践-安全最佳实践-sVirt保护

    文章目录 52 最佳实践 安全最佳实践 sVirt保护 52 1 概述 52 2 开启sVirt保护 52 2 1 开启主机的SELinux 52 2 2 创建开启sVirt功能的虚拟机 52 2 3 确认sVirt开启成功 52 最佳实践
  • Blender interface界面介绍

    Blender interface界面介绍 Blender的主界面 cycles 渲染引擎 有噪点 但是他的渲染效果会很好 因为他是光线追踪 模拟真实的漫反射 实时渲染 evee 2 08过后软件才出的 渲染图层 场景 世界 其中 会用到很
  • 测试理论基础学习

    软件测试概述 一 软件测试的定义 软件测试是为了发现错误而针对某个程序或系统的执行过程 其目的在于检验它是否满足规定的需求 二 软件测试的原则 1 穷举测试是不可能的 2 测试用例的设计是关键 3 缺陷具有免疫性 测试用例要不断更新 4 对
  • Exchange2010/2013/2016删除指定主题邮件

    Exchange2010 2013 2016删除指定主题邮件 说到Exchange服务 大家并不陌生了 但是作为一个Exchange管理员的话 随时都在学习中 近期有个问题 用户发错邮件了 说能不能把用户收到的主题邮件进行删除 所以就同意帮
  • Hyperledger Fabric文档v2.2(四)

    入门 参考博文 搭建 Fabric 测试网络 在我们开始之前 如果您还没有这样做 您可能希望检查您是否已经在将要开发区块链应用程序或运行 Hyperledger Fabric 的平台上安装了所有 准备阶段 安装必备组件后 即可下载并安装 H
  • HashSet、LinkedHashSet、TreeSet使用区别

    HashSet 哈希表是通过使用称为散列法的机制来存储信息的 元素并没有以某种特定顺序来存放 LinkedHashSet 以元素插入的顺序来维护集合的链接表 允许以插入的顺序在集合中迭代 TreeSet 提供一个使用树结构存储Set接口的实
  • Cobalt Strike(CS)介绍,安装及初步使用(学习笔记1)

    目录 CS简介 2 安装使用 CS简介 Cobalt Strike 简称CS 是一个为对手模拟和红队行动而设计的平台 主要用于执行有目标的攻击和模拟高级威胁者的后渗透行动 分为服务器和客户端 模式 Cobalt Strike使用C S架构
  • 微信小程序-入门篇(app.wxml及app.wxss)

    app wxml相当于我们的app中的xml文件内容 看了大半天的界面代码感觉还是不太适应这种js风格的东西 不过以后了解多了估计就好些了 我们首先介绍 wxml内容 有句文档上的话很重要 WXML 中的动态数据均来自对应 Page 的 d
  • 国际化动态加载数据

    国际化动态加载数据 起因 公司业务涉及比较广泛 所做网页必然要涉及到国际化 国际化本是老生常谈的内容 但是我们大部分做的都是静态数据国际化 或者联网插件国际化 而很多公司 属于内网开发 故而只能静态数据 但是整个项目很大 很多时候静态数据太
  • win10通过命令或通过控制面板关闭防火墙

    1 点击控制面板 Win键 R 输入control enter 点击防火墙 打开或关闭防火墙 关闭防火墙 2 通过命令关闭防火墙 关闭防火墙 netsh firewall set opmode mode disable 查看防火墙状态 Ne
  • 总结之Linux环境(一)——命令行

    从一开始学习linux到现在 已经有很多时间没有碰linux系统了 这个陌生感让人很不适 以前也没有写什么总结 再接触还是也个总结对以后使用根据方便 搬运某培训机构资料 又快又全 Linux 的五个重启命令 1 shutdown shutd
  • c++11多线程编程(十):packaged_task<>介绍与实例

    本节讨论c 11中std packaged task的特性与使用方法 std packaged task lt gt std packaged task lt gt 是一个类模板 代表一个异步任务 封装了 1 可调用实体 即函数 lambd