当前位置: 首页 > news >正文

【仿RabbitMQ消息队列】基于C++11中packaged_tack异步线程池

目录

什么是同步和异步?

future

使用future和async配合管理异步任务

使用promise和future配合管理异步任务

使⽤std::packaged_task和std::future配合

C++11异步线程池


什么是同步和异步?

同步(Synchronous)

同步编程是指程序按照代码的顺序,一步步执行,每一步必须等待上一步执行完毕,才能执行下一步。在同步操作中,如果某个任务(如I/O操作、网络请求等)需要等待(比如等待磁盘读写完成、等待网络响应等),程序就会阻塞在那里,直到该任务完成,才能继续执行后续的代码。这种方式简单直观,但效率较低,尤其是在处理需要长时间等待的任务时,会导致程序响应变慢或“假死”。

异步(Asynchronous)

异步编程则允许程序在等待某个长时间运行的操作(如文件I/O、网络请求等)完成时,继续执行后续的代码,而不会阻塞当前线程。当异步操作完成时,通常通过回调函数、Promises、Future、async/await等方式来通知程序,以便执行后续依赖于该操作结果的操作。这种方式可以提高程序的效率和响应性,尤其是在处理多个并发任务时。


future

介绍

std::future是C++11标准库中的⼀个模板类,它表⽰⼀个异步操作的结果。当我们在多线程编程中使⽤异步任务时,std::future可以帮助我们在需要的时候获取任务的执⾏结果。std::future的⼀个重要特性是能够阻塞当前线程,直到异步操作完成,从⽽确保我们在获取结果时不会遇到未完成的操作。

简单来说:future就是可以用来获取一个异步任务/函数的结果的;

应用场景:

  • 异步任务: 当我们需要在后台执⾏⼀些耗时操作时,如⽹络请求或计算密集型任务等,std::future可以⽤来表⽰这些异步任务的结果。通过将任务与主线程分离,我们可以实现任务的并⾏处理,从⽽提⾼程序的执⾏效率
  • 并发控制: 在多线程编程中,我们可能需要等待某些任务完成后才能继续执⾏其他操作。通过使⽤std::future,我们可以实现线程之间的同步,确保任务完成后再获取结果并继续执⾏后续操作
  • 结果获取:std::future提供了⼀种安全的⽅式来获取异步任务的结果。我们可以使⽤std::future::get()函数来获取任务的结果,此函数会阻塞当前线程,直到异步操作完成。这样,在调⽤get()函数时,我们可以确保已经获取到了所需的结果

使用future和async配合管理异步任务

std::async是⼀种将任务与std::future关联的简单⽅法。它创建并运⾏⼀个异步任务,并返回⼀个与该任务结果关联的std::future对象。默认情况下,std::async是否启动⼀个新线程,或者在等待future时,任务是否同步运⾏都取决于你给的 参数。这个参数为std::launch类型:

  • std::launch::deferred 表明该函数会被延迟调⽤,直到在future上调⽤get()或者wait()才会开始执⾏任务
  • std::launch::async 表明函数会在⾃⼰创建的线程上运⾏
  • std::launch::deferred | std::launch::async 内部通过系统等条件⾃动选择策略
#include <iostream>
#include <thread>
#include <future>
#include<chrono>
using namespace std;
int Add(int num1, int num2)
{cout << "加法" << endl;return num1 + num2;
}
int main()
{// 两个版本// 函数+不定参数// 策略+函数+不定餐cout<<"first "<<endl;//deferred: 在执行get获取异步结果的时候才会执行异步任务//async: 内部会创建工作线程异步完成任务future<int> result = async(std::launch::deferred, Add, 11, 22);// 返回值是什么参数就是什么std::this_thread::sleep_for(chrono::seconds(1));cout<<"two"<<endl;int sum=result.get();cout<<"three"<<endl;cout<<sum<<endl;return 0;
}

使用promise和future配合管理异步任务

std::promise提供了⼀种设置值的⽅式,它可以在设置之后通过相关联的std::future对象进⾏读取。换种说法就是之前说过std::future可以读取⼀个异步函数的返回值了, 但是要等待就绪, ⽽std::promise就提供⼀种 ⽅式⼿动让 std::future就绪

我们可以把promise理解为主线程给另一个执行异步任务函数线程放返回值的篮子,但是这个篮子交给另一个线程后无法在给回来,因此主线程需要用promise创建一个future工具从这个篮子中去取返回值

#include<iostream>
#include<thread>
#include<future>
using namespace std;
void Add(int num1,int num2,promise<int> &prom)
{prom.set_value(num1+num2);return ;
}
int main()
{promise<int> prom;future<int> fu=prom.get_future();thread t1(Add,11,22,ref(prom));int res = fu.get();cout<<"sum: "<<res<<endl;t1.join();return 0;
}

使⽤std::packaged_task和std::future配合

std::packaged_task就是将任务和 std::feature 绑定在⼀起的模板,是⼀种对任务的封装。我们可以通过std::packaged_task对象获取任务相关联的std::feature对象,通过调⽤get_future()⽅法获得。std::packaged_task的模板参数是函数签名。

可以把std::future和std::async看成是分开的, ⽽ std::packaged_task则是⼀个整体。

#include<iostream>
#include<thread>
#include<future>
#include<memory>
using namespace std;
//package_task是一个模板类,实例化的对象可以对一个函数进行二次封装
int Add(int num1,int num2)
{return num1+num2;
}
int main()
{auto ptask = make_shared<packaged_task<int(int,int)>>(Add);future<int> fu = ptask->get_future();thread thr([ptask](){(*ptask)(11,22);});int sum = fu.get();cout<<sum<<endl;thr.join();return 0;
}

C++11异步线程池

对于普通的线程池我们只是将任务交给线程执行即可,但是如果我们想要获取任务执行的返回值就要进行类似上面的异步处理;基于线程池执⾏任务的时候,⼊⼝函数内部执⾏逻辑是固定的,因此选择std::packaged_task加上std::future的组合来实现。

线程池工作思想

⽤⼾传⼊要执⾏的函数,以及需要处理的数据(函数的参数),由线程池中的⼯作线程来执⾏函
数完成任务

实现

管理成员

  • 任务池:⽤vector维护的⼀个函数任务池⼦
  • 互斥锁 & 条件变量: 实现同步互斥
  • ⼀定数量的⼯作线程:⽤于不断从任务池取出任务执⾏任务
  • 结束运⾏标志:以便于控制线程池的结束

管理的操作

  • ⼊队任务:⼊队⼀个函数和参数
  • 停⽌运⾏:终⽌线程池

完整代码

class threadpool
{
public:using Functor = std::function<void(void)>;threadpool(int thr_count = 1) : _stop(false){for (int i = 0; i < thr_count; i++){_threads.emplace_back(&threadpool::entry, this);}}~threadpool(){stop();}void stop(){if (_stop == true)return;_stop = true;_cv.notify_all();// 等待所有线程退出for (auto &thread : _threads){thread.join();}}// push传入的首先有一个函数// 不定参数表示要传入函数的参数// push函数内部会将这个传入的函数封装成一个异步任务,抛入任务池中,由工作线程取出执行// 使用lambda表达式生成一个可调用对象,抛入到任务池中,由工作线程取出进行执行// 入队// 函数类型// 参数包template <typename F, typename... Args>auto push(F &&func, Args &&...args) -> std::future<decltype(func(args...))>{// 1.将传入的函数封装一个packaged_task任务using return_type = decltype(func(args...)); // 退出函数返回值对象auto tmp_func = std::bind(std::forward<F>(func), std::forward<Args>(args)...);auto task = std::make_shared<std::packaged_task<return_type()>>(tmp_func);std::future<return_type> fu = task->get_future();// 2。构造一个lambda表达式(捕获任务对象),函数内执行任务对象{std::unique_lock<std::mutex> lock(_mutex);// 3.将构造出来的匿名函数对象,抛入到任务池中_taskpool.push_back([task](){ (*task)(); });_cv.notify_one();}return fu;}private:// 线程入口函数// 不断地从任务池中取任务进行执行void entry(){while (!_stop){std::vector<Functor> tem_taskpool;{// 加锁std::unique_lock<std::mutex> lock(_mutex);// 等待:等待任务池不为空,或者_stop被置位_cv.wait(lock, [this](){ return _stop || !_taskpool.empty(); });// 取出任务执行tem_taskpool.swap(_taskpool);}for (auto &task : tem_taskpool){task();}}}private:std::atomic<bool> _stop;std::vector<Functor> _taskpool; // 任务池std::mutex _mutex;std::condition_variable _cv;std::vector<std::thread> _threads; // 线程池
};

上面异步线程池的完整代码中的语法规则都是C++11的新特性,在核心功能中甚至一行都有好几个的C++11新特性,要想理解上面的代码需要我们非常熟悉新特性;


今天对C++11异步线程池的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

相关文章:

【仿RabbitMQ消息队列】基于C++11中packaged_tack异步线程池

目录 什么是同步和异步&#xff1f; future 使用future和async配合管理异步任务 使用promise和future配合管理异步任务 使⽤std::packaged_task和std::future配合 C11异步线程池 什么是同步和异步&#xff1f; 同步&#xff08;Synchronous&#xff09; 同步编程是指程…...

免费下载专利

给大家提供一个可以免费下载专利的地方 链接&#xff1a;https://www.drugfuture.com/cnpat/cn_patent.asp...

CentOS7安装流程步骤详细教程

1. 简介 1.1. 概述 CentOS 7是一款基于Red Hat Enterprise Linux(RHEL)的开源Linux发行版,它提供了一个稳定、安全、高效的操作系统,适用于企业级应用、服务器、云计算等领域。CentOS 7以其高度的稳定性和安全性而闻名,它广泛应用于各种行业和领域,包括政府、金融、医疗、…...

【大模型从入门到精通17】openAI API 构建和评估大型语言模型(LLM)应用5

这里写目录标题 理论问题&#xff1a;实践问题&#xff1a;理论实践 理论问题&#xff1a; 1.描述评估LLM应用程序输出的重要性&#xff0c;并提及至少三个维度&#xff0c;这些输出应该在这几个维度上被评估。 2.解释在评估LLM应用程序时开发稳健的性能指标的作用&#xff0c…...

苹果手机无iCloud备份下“最近删除”照片的恢复策略

iPhone最近删除清空了照片还能恢复吗&#xff1f;大家都知道&#xff0c;照片对于我们来说是承载着美好回忆的一种形式。它记录着我们的平淡生活&#xff0c;也留住了我们的美好瞬间&#xff0c;因此&#xff0c;具有极其重要的纪念价值。但由于我们的失误操作导致照片被删除&a…...

Docker搭建Minio容器

Docker搭建Minio容器 前言 在上一集我们介绍了分布式文件存储行业解决方案以及技术选型。最终我们决定选用Minio作为分布式文件存储。 那么这集我们就在Docker上搭建Minio容器即可。 Docker搭建Minio容器步骤 创建Minio文件目录 我们选择创建/minio/data目录 修改目录权…...

【C++】多源BFS问题和拓扑排序

目录 多源BFS介绍 单源BFS和多源BFS的区别 SO如何解决多源BFS问题 多源之核心 矩阵 算法思路 代码实现 飞地的数量 算法思路 代码实现 地图中的最高点 算法思路 代码实现 地图分析 算法思路 代码实现 拓扑排序介绍 有向无环图 ​编辑 如何解决这类问题 课…...

CentOS 7 安装详细教程

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; CentOS 7 是一个稳定的企业级 Linux 发行版&#xff0c;广泛用于服务器环境。CentOS 7 是基于 Red Hat Enterprise Linux (RHEL) 构建的企业级 Linux 发行版&#xff0c;提供免费的、开源的操作系统&#xf…...

mybatis-plus + springboot 多对多实例

在MyBatis Plus中&#xff0c;自动填充数据是一种非常实用的功能&#xff0c;它可以自动地为一些字段设置默认值&#xff0c;比如创建时间和更新时间。对于多对多关系来说&#xff0c;虽然自动填充主要针对单一实体的字段&#xff0c;但在某些情况下&#xff0c;你可能也需要在…...

SpringBoot日志整合

Spring Boot 整合日志框架的核心是通过 spring-boot-starter-logging 依赖来实现的&#xff0c;它默认整合了 Logback 日志框架。 Spring Boot 对各种日志框架进行了自动配置&#xff0c;使得我们可以很容易地在 Spring Boot 应用中使用日志。 Spring Boot 在类路径下寻找 Log…...

信创教育:培养未来科技创新的生力军

随着全球数字化转型的加速&#xff0c;信息技术应用创新&#xff08;简称“信创”&#xff09;产业作为推动国家信息技术自主可控和产业升级的关键领域&#xff0c;正迎来前所未有的发展机遇。信创教育&#xff0c;作为培养未来科技创新生力军的重要阵地&#xff0c;其重要性和…...

slowfast

核心网络网络架构: 1、分别获取高频和低频图像数据 2、分别进行特征提取 3、特征融合 4、预测 网络结构细节&#xff1a;...

怎么调试python脚本

打开pycharm community 2019.1软件&#xff0c;创建一个项目。 创建一个py后缀的文件作为示范&#xff0c;文件名自己定义。 编写代码&#xff0c;然后右键点击进行运行&#xff0c;查看一下是否有问题。 点击右上角的虫子图标&#xff0c;然后下面会有控制面板出来&#xff0c…...

Flask获取请求信息

示例代码 from flask import Flaskapp = Flask(__name__)if __name__ == "__main__": app.run(debug=True) 1、获取请求头 from flask import request@app.route("/headers", methods=["GET"])def get_headers(): headers = request.heade…...

Overleaf中放置高分辨率图片的方法

如果将ppt中的图片另存为png或jpg等格式&#xff0c;如果图中有密集的编码网格&#xff0c;则生成的pdf会糊掉。如何确保生成的pdf中的图片放大后仍然保持细节&#xff1f;亲测方案&#xff1a; 1、将ppt中的图片尺寸记下来&#xff0c;然后在ppt→设计中将ppt模板的大小设置成…...

【C语言】动态内存管理(malloc,free,calloc,realloc详解 )

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html &#x1f381;代码托管:C语言: C语言方向&#xff08;基础知识和应用&#xff09; (gitee.com) ⚙️操作环境:Visual Studio 2022 目录 一、…...

如何寻找数值仿真参数最优解?CFD参数优化详解3来袭

本期文章将通过2个简单案例演示参数优化的操作步骤&#xff0c;一起来看看吧&#xff01; 流程自动化 实现 CFD 参数优化&#xff0c;首先要创建流程自动化。用户可采用SimLab的Python宏命令&#xff0c;录制建模流程。或在HyperWorks CFD模块的Template Manager创建Tcl/Tk命令…...

虚拟机macos中构建llvm、clang并配置Xcode

安装虚拟机macos&#xff0c;并安装brew&#xff1a; 安装vmware&#xff1a;https://www.bilibili.com/video/BV1Wo4y1E7fc/安装最新版的macos&#xff1a;极限苹果-Mac论坛-提供Mac软件和macOS苹果系统镜像下载下载并安装brew&#xff1a;版本要低&#xff0c;我装的是4.3.5…...

Java 中的 @SneakyThrows 注解详解:简化异常处理的利与弊

在 Java 开发中&#xff0c;异常处理是一个不可避免的重要部分。我们经常需要处理各种检查型异常&#xff08;checked exceptions&#xff09;&#xff0c;这有时会导致代码变得冗长且难以维护。为了简化异常处理&#xff0c;Lombok 提供了一个强大的注解——SneakyThrows。本文…...

系统编程 day11 进程(线程)3

fork函数的总结&#xff1a; 总结对进程学习之中的回收函数wait wait函数&#xff1a; 1.获取子进程的退出状态 2.回收资源------会让僵尸态的子进程销毁 注&#xff1a;1.wait函数本身是一个阻塞操作&#xff0c;会使调用者阻塞 2.父进程要获得子进程的退出状态 子进程&…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...