std::async 和 std::packaged_task

0、背景

在现代 C++ 中,std::async 和 std::packaged_task 是两个非常重要的工具,能够帮助我们更好地处理并发和异步操作。它们分别代表了异步执行任务的两种不同的方式,但都可以有效地将任务的执行从主线程或调用线程中分离出来,以提高程序的并发性和响应能力。

1、std::async

1.1、std::async的基本语法

std::async 是 C++11 引入的一个函数模板,它用于启动一个异步操作,并返回一个 std::future 对象,这个 future 对象可以用来获取异步操作的结果。std::async 会根据指定的策略异步地执行一个函数或可调用对象。函数签名如下:

std::future<T> std::async(std::launch policy, Func&& f, Args&&... args);
  • policy: 启动策略,决定任务如何执行。它有两个可能的值:
    std::launch::async:表示任务将异步执行(即在一个新的线程中执行);
    std::launch::deferred:表示任务将延迟执行,直到调用 future.get() 或 future.wait() 来获取结果时才开始执行。
  • f: 一个可调用对象(例如函数指针、lambda 表达式或函数对象)。
  • args: 传递给可调用对象的参数
    std::async 返回一个 std::future 类型的对象,T 是任务的返回类型。可以通过 future.get() 来获取任务的结果。需要注意的是,如果任务还没有完成,调用 get() 会阻塞直到任务完成。

1.2、使用用例

#include <iostream>
#include <future>
#include <thread>int async_task(int x, int y) {std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟耗时任务return x + y;
}int main() {// 启动异步任务std::future<int> result = std::async(std::launch::async, async_task, 5, 3);// 在等待异步结果的同时,可以做其他工作std::cout << "Doing other work in main thread..." << std::endl;// 获取异步任务结果,get() 会阻塞直到任务完成int sum = result.get();std::cout << "Async task result: " << sum << std::endl;return 0;
}

在上面的例子中,std::async 启动了一个异步任务,并返回一个 std::future 对象,主线程可以在不阻塞的情况下继续做其他工作,直到调用 result.get() 时才会等待异步任务的完成并获取结果。

1.3、启动策略

std::launch 是一个枚举,决定任务的执行方式。

  • std::launch::async:表示任务应该在独立的线程中异步执行。也就是说,当调用 std::async(std::launch::async, func) 时,func 会在一个新的线程中执行
  • std::launch::deferred:表示任务会被延迟到调用 future.get() 或 future.wait() 时才执行。即任务不会在调用 std::async 时立即启动,而是在获取结果时才启动。

2、std::packaged_task

2.1、std::packaged_task的基本语法

std::packaged_task 是 C++11 中的另一项异步操作工具,它封装了一个可调用对象,并提供一个 std::future 来获取异步操作的结果。与 std::async 不同,std::packaged_task 并不自动启动任务,调用者需要手动执行该任务。基本语法如下:

template <typename F>
class std::packaged_task;
  • F: 一个可调用对象的类型(例如函数指针、lambda 表达式等)。
  • std::packaged_task 封装了一个任务,并且提供了 get_future() 方法来获取对应的 std::future 对象。

2.2、使用例子

#include <iostream>
#include <future>
#include <thread>int task(int x, int y) {std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟耗时任务return x + y;
}int main() {// 创建 packaged_task 对象std::packaged_task<int(int, int)> task_obj(task);// 获取与 packaged_task 关联的 future 对象std::future<int> result = task_obj.get_future();// 启动新线程来执行任务std::thread t(std::move(task_obj), 5, 3);// 在等待异步结果的同时,可以做其他工作std::cout << "Doing other work in main thread..." << std::endl;// 获取异步任务结果,get() 会阻塞直到任务完成int sum = result.get();std::cout << "Task result: " << sum << std::endl;// 等待线程结束t.join();return 0;
}

我们使用 std::packaged_task 封装了一个任务 task,然后调用 get_future() 获取一个 std::future 对象。任务并不会自动执行,因此我们需要显式地创建一个线程来执行这个任务。最后,我们通过 result.get() 获取结果,get() 会阻塞直到任务完成。

2.3、启动策略

std::async 自动处理线程的创建和管理,而 std::packaged_task 则要求手动创建线程并执行任务。std::async 可以选择任务延迟执行(通过 std::launch::deferred),而 std::packaged_task 始终会在调用时被启动

3、std::async 和 std::packaged_task 对比

特性std::asyncstd::packaged_task
任务启动时机自动启动,可以选择异步执行或延迟执行任务需要手动启动(通过线程或其他方式)
线程管理自动管理线程需要显式创建线程来执行任务
返回结果返回一个 std::future 对象,直接可以获取结果返回一个 std::future 对象,需要通过线程来执行任务
使用场景简单的异步任务,适用于无需控制线程生命周期的场景需要显式控制任务执行时机和线程的场景
启动策略std::launch::async 或 std::launch::deferred不支持延迟执行,只能同步启动

4、使用场景

4.1、std::async 的使用场景

  • 当你只关心任务的异步执行,而不需要显式控制线程时,std::async 是一个非常方便的选择。
  • 它适用于简单的并发任务,且希望任务自动执行,不需要管理线程的生命周期。

4.2、std::packaged_task 的使用场景

  • 当你需要手动控制任务的执行时,例如当你希望任务在某个特定时刻或者通过某种特定的方式(如通过线程池)来启动时,std::packaged_task 会是一个合适的选择。
  • 它适用于需要与线程池、事件驱动等复杂并发机制一起使用的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows上安装Redis

下载&#xff1a;https://github.com/tporadowski/redis&#xff08;官方不提供windows版&#xff09; 配置文件里设置密码&#xff1a;requirepass 123456 添加服务的命令&#xff1a; redis-server --service-install redis.windows-service.conf --loglevel verbose (--serv…

TypeScript 与 JavaScript

文章目录 一、为 JavaScript 库添加类型定义(一)什么是类型定义文件(.d.ts 文件)(二)手动编写类型定义和使用现有类型定义(如 DefinitelyTyped)手动编写类型定义使用现有类型定义(如 DefinitelyTyped)二、在 TypeScript 项目中使用流行的 JavaScript 库(如 jQuery、…

从源码构建安装Landoop kafka-connect-ui

背景 部署Landoop kafka-connect-ui最简单的办法还是通过docker来部署&#xff0c;我们之前的kafka-connect-ui就是通过docker部署的&#xff0c;但是&#xff0c;最近发现个问题&#xff1a;当使用docker部署且防火墙使用的是firewalld的情况下&#xff0c;就会出现端口冲突。…

算法—动态规划

一、简介 动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种通过将原问题分解为若干个子问题来求解最优化问题的算法思想。动态规划常常用于解决那些可以被分解为更小的重叠子问题的场景。 与分治法的区别在于&#xff0c;分治法会将问题分解成独…

Android GO 版本锁屏声音无效问题

问题描述 Android go版本 在设置中打开锁屏音开关&#xff0c;息屏灭屏还是无声音 排查 vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\keyguard\KeyguardViewMediator.java private void setupLocked() {...String soundPath Settings.G…

使用 NVIDIA DALI 计算视频的光流

引言 光流&#xff08;Optical Flow&#xff09;是计算机视觉中的一种技术&#xff0c;主要用于估计视频中连续帧之间的运动信息。它通过分析像素在时间维度上的移动来预测运动场&#xff0c;广泛应用于目标跟踪、动作识别、视频稳定等领域。 光流的计算传统上依赖 CPU 或 GP…

Tomcat的安装即使用

Tomcat的概念 Tomcat服务器是Java语言开发的&#xff0c;免费的开放源代码的Web应用服务器。 Tomcat处理静态HTML的能力远不及Apache或者Nginx&#xff0c;通常是作为一个Servlet和JSP容器&#xff0c;单独运行在后端。 Tomcat是由三个功能组合而成&#xff1a; java servlet&…

Linux:进程(环境变量、程序地址空间)

目录 冯诺依曼体系结构 操作系统 设计操作系统的目的 操作系统的管理 进程 PCB fork 进程状态 进程状态查看 僵尸进程 孤儿进程 进程优先级 查看、修改进程优先级命令 竞争、独立、并行、并发 进程切换 活动队列和运行队列 活动队列 过期队列 active指针…

对于使用exe4j打包,出现“NoClassDefFoundError: BOOT-INF/classes”的解决方案

jar使用exe4j打包exe&#xff0c;出现NoClassDefFoundError: BOOT-INF/classes 注意选取的jar包是使用build&#xff0c;而不是maven中的install 本文介绍解决这个方法的方案 点击Project Structure 按照如图所示选择 选择main class&#xff0c;选择你要打的main 如果遇到/M…

SpringBoot 编程式事务使用

目录 1. 简介2. TransactionTemplate 方式3. TransactionManager 方式4. 事务传播行为5. 事务隔离级别6. 最佳实践7. 常见问题与解决方案 1. 简介 编程式事务管理是通过编写代码来管理事务&#xff0c;相对于声明式事务&#xff08;Transactional注解&#xff09;&#xff0…

uniapp连接蓝牙操作(蓝牙设备地锁)

介绍&#xff1a; 本文采用uni-app框架来创建一个简单的用户界面&#xff0c;用于搜索、连接和发送命令给蓝牙设备。 1.打开蓝牙适配器 function openBluetooth() {uni.openBluetoothAdapter({success() {uni.offBluetoothDeviceFound();// 监听新设备发现事件uni.onBlueto…

web:pc端企业微信登录-vue版

官方文档&#xff1a;developer.work.weixin.qq.com/document/pa… 不需要调用ww.register&#xff0c;直接调用ww.createWWLoginPanel即可创建企业微信登录面板 - 文档 - 企业微信开发者中心 (qq.com) 引入 //通过 npm 引入 npm install wecom/jssdk import * as ww from we…

登陆harbor发现证书是错误的, 那么如何更新harbor的证书呢

Error response from daemon: Get "https://172.16.21.35/v2/": tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, 172.16.21.30, not 172.16.21.35 版本 v2.10.1-b7b88476 不需要从头看, 直接看最下面的成功的证书创建 这里面首…

外观模式的理解和实践

外观模式&#xff08;Facade Pattern&#xff09;是一种常用的软件设计模式&#xff0c;它提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口。该模式定义了一个高层的接口&#xff0c;使得子系统更容易使用。简单来说&#xff0c;外观模式就是通过引入一个外观角色…

excel使用笔记

1.工作表1计算工作表2某列的和 假设我们有两个工作表&#xff0c;分别命名为“Sheet1”和“Sheet2”&#xff0c;我们想要求和这两个工作表中A1到A**单元格的数据&#xff0c;可以在任意一个工作表的单元格中输入以下公式&#xff1a; SUM(Sheet1!A1:A10, Sheet2!A1:A10) SUM…

《应用导航设计:裂变式路由风暴来袭》——HarmonyOS开发项目时的Navigation路由奇妙使用

文章目录 应用导航设计引言概述场景示例基本实现推荐方案路由管理模块的实现页面跳转实现 业务实现中的关键点动态加载路由栈管理 应用导航设计 引言 在大型应用开发中&#xff0c;如何高效地设计应用导航&#xff0c;处理多模块间的路由跳转与解耦&#xff0c;始终是一个关键…

【腾讯云】AI驱动TDSQL-C Serveress 数据库技术实战营-如何是从0到1体验电商可视化分析小助手得统计功能,一句话就能输出目标统计图

欢迎来到《小5讲堂》 这是《腾讯云》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景效果图流程图创建数据库基本信息数据库配置设置密码控制台开启…

XSLT 编辑 XML

XSLT 编辑 XML 介绍 XSLT&#xff08;可扩展样式表语言转换&#xff09;是一种用于转换XML文档的语言。它允许开发人员将XML数据转换为其他格式&#xff0c;如HTML、PDF或纯文本。XSLT通过使用XPath查询来定位XML文档中的元素&#xff0c;并对这些元素应用转换规则。在本教程…

thinkphp8自带分页bootstrap

tp8引用的是bootstrap3.4.1这个版本&#xff1b; 前端结构&#xff1a; <ul class"pagination"><li><a href"/index.php?page4"></a></li><li><a href"/index.php?page1">1</a></li>…

win服务器的架设、windows server 2012 R2 系统的下载与安装使用

文章目录 windows server 2012 R2 系统的下载与安装使用1 windows server 2012 的下载2 打开 VMware 虚拟机软件&#xff08;1&#xff09;新建虚拟机&#xff08;2&#xff09;设置虚拟机&#xff08;3&#xff09;打开虚拟机 windows server 2012&#xff08;4&#xff09;进…