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

多线程模板应用实现(实践学习笔记)

出处:B站码出名企路

个人笔记:因为是跟着b站的教学视频以及文档初步学习,可能存在诸多的理解有误,对大家仅供借鉴,参考,然后是B站up阳哥的视频,我是跟着他学。大家有兴趣的可以到b站搜索。加油,一起学习。我的问题,大家如果看见,希望可以提出指正,谢谢大家。

应用场景

多线程的应用场景非常多,常见的有:

  1. 网络通信:在网络通信应用中,一般需要同时处理多个请求,如果使用单线程模式,会阻塞其他请求,造成性 能瓶颈,因此使用多线程可以提高并发处理能力。

  2. 数据库操作:在数据库操作中,有时需要同时对多个数据表进行操作,使用多线程可以提高处理效率。

  3. 图像处理:在图像处理应用中,需要对多个图像进行处理,在单线程模式下,处理速度会很慢,使用多线程可 以提高处理速度。

  4. 游戏开发:在游戏开发中,常常需要同时处理多个任务,比如处理游戏画面、物理效果、声音效果等,使用多 线程可以提高游戏的运行速度和流畅度。

  5. 并行计算:在科学计算领域中,常常需要对大量数据进行处理和计算,使用多线程可以将计算任务划分到多个 线程中进行,从而提高计算速度。

总之,多线程在提高程序性能、响应性和资源利用率方面有着广泛的应用。然而,需要注意在多线程编程中处理线程同步、共享数据等问题,以确保程序的正确性和稳定性。

图解结构

模块拆解

第一步:StateSubmitor耗时内容处理类

此处并没有很多具体实现,因为要结合业务。比如耗时处理逻辑

  class StateSubmitor    {public:explicit StateSubmitor(const std::string& str);~StateSubmitor();//submit: 提交到队列中//const std::string& content 内容,包括海量数据void submit(const std::string& content);//content可任意//flush: 将队列中的所有状态信息发往远程收集端//具体的业务逻辑void flush();private:StateSubmitor(const StateSubmitor&) = delete;StateSubmitor& operator=(const StateSubmitor&) = delete;};
    void StateSubmitor::submit(const std::string& content){/*@ 对 content的耗时处理逻辑*/}
第二步:NodeMonitor线程启动类
//节点监控, 监控任务的发生, 业务的产生. 多线程同步等控制逻辑的封装class NodeMonitor{public:~NodeMonitor();static NodeMonitor* instance();void start();void shutdown();bool init();private:NodeMonitor();NodeMonitor(const NodeMonitor&) = delete;NodeMonitor& operator=(const NodeMonitor&) = delete;void stateInfo(const std::string& strs);void ThreadFunc();                         //消费者线程入口函数bool shutdown_;                            //开关   std::mutex mutex_;                         std::thread thread_;                       //消费者线程std::condition_variable cond_;//queuestd::queue<std::string> task_queue_;       //任务队列std::unique_ptr<StateSubmitor> submitor_;  //unique_ptr管理submitor对象};}

具体实现,这里才是多线程同步互斥的重点部分,核心,利用任务队列做缓冲容器,解耦合。使得生产者线程和消费者线程之间的耦合度降低,生产者只管将任务放入任务队列,然后即可返回,无需等待消费者处理。消费者只管从任务队列中拿取任务处理。大大提高效率。通过缓存大大减低了生产者和消费者之间的耦合程度。

生活场景:快递驿站,快递小哥就是生产者,我们就是消费者。快递驿站就是容器队列。

 //析构一般独立一个函数NodeMonitor::~NodeMonitor(){this->shutdown();//做资源释放等等操作}//创建线程安全的单例//call_once 确保多线程下仅仅创建一个NodeMonitor对象NodeMonitor* NodeMonitor::instance(){static NodeMonitor* instance = nullptr;static std::once_flag flag;  std::call_once(flag, [&]{instance = new (std::nothrow) NodeMonitor();});return instance; }//线程启动void NodeMonitor::start(){//创建消费者thread_ = std::thread(&NodeMonitor::ThreadFunc, this);//启动生产者if (!init()){return;}}//生产者函数bool NodeMonitor::init(){submitor_.reset(new StateSubmitor("lyy")); //创建submitor/*@ 不断地填充stateInfo@ 如果是实际应用场景可能会采取轮询, 或者是event事件触发, 此处阳哥按照最简单的塞入文本信息作为事件(任务)*/while (true){stateInfo("lxk");}return true;}//填入需要的信息 <=> push任务void NodeMonitor::stateInfo(const std::string& strs){std::unique_lock<std::mutex> lock(mutex_);task_queue_.push(strs); //生产, 塞入任务cond_.notify_one();     //通知消费}//线程销毁void NodeMonitor::shutdown(){std::unique_lock<std::mutex> lock(mutex_);shutdown_ = true;cond_.notify_all();if (thread_.joinable()){thread_.join();}}//消费者函数void NodeMonitor::ThreadFunc(){while (!shutdown_){std::unique_lock<std::mutex> lock(mutex_);cond_.wait(lock, [this]{return shutdown_ || !task_queue_.empty();});if (shutdown_){break;}std::string str = task_queue_.front();task_queue_.pop();lock.unlock();submitor_->submit(str);//提交状态信息}}

具体案例

消息队列作业实现

#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
#include <memory>
#include <condition_variable>
#include <string>
#include <chrono>namespace XX
{class MessageQueue {//封装消息队列类public:void push(const std::string& message); std::string pop(); bool empty();private:std::mutex mutex_; //互斥锁, 保障互斥操作std::condition_variable cond_; //通知, 保障同步std::queue<std::string> msg_queue_;  //容器};class StateSubmitor {//消息处理类, 业务处理, 管理消息队列public:explicit StateSubmitor(MessageQueue& msg_queue);~StateSubmitor();void submit(const std::string& content); //提交状态信息并将其添加到队列中void flush();  //flush: 将队列中的所有状态信息发往远程收集端, 清空处理所有消息.private:StateSubmitor(const StateSubmitor &) = delete;StateSubmitor &operator=(const StateSubmitor &) = delete;private:MessageQueue& msg_queue_;  //消息队列};// 节点监控, 监控任务的发生, 业务的产生. 多线程同步等控制逻辑的封装class NodeMonitor {public:~NodeMonitor();static NodeMonitor *instance();void start();void shutdown();bool init();private:NodeMonitor();void ProducerThreadFunc(); //线程函数void ConsumerThreadFunc(); //线程函数NodeMonitor(const NodeMonitor &) = delete;NodeMonitor &operator=(const NodeMonitor &) = delete;private:std::thread producer_thread_; //生产者线程,不停的往消息队列塞入监控到的用户状态信息消息.static int count_;std::unique_ptr<StateSubmitor> submitor_;MessageQueue msg_queue_; //消息队列std::thread consumer_thread_;//消费者线程, 不停的从消息队列中抽出消息进行处理bool shutdown_;              //开关};
}namespace XX {int NodeMonitor::count_ = 0;//初始化void MessageQueue::push(const std::string& message) {std::unique_lock<std::mutex> lock(mutex_);msg_queue_.push(message);//塞入消息cond_.notify_one();//通知消费}std::string MessageQueue::pop() {std::unique_lock<std::mutex> lock(mutex_);cond_.wait(lock, [this]{//等待消息到来return !empty();});std::string msg = msg_queue_.front();//拿到消息msg_queue_.pop();return msg;}bool MessageQueue::empty() {return msg_queue_.empty();}StateSubmitor::StateSubmitor(MessageQueue& msg_queue): msg_queue_(msg_queue) {}  void StateSubmitor::submit(const std::string& content) {//提交状态信息消息的业务操作std::cout << "消息为: " << content << std::endl;//将业务状态消息push到消息队列中msg_queue_.push(content);}void StateSubmitor::flush() {//清空所有消息}StateSubmitor::~StateSubmitor() {this->flush();}NodeMonitor::NodeMonitor():shutdown_(false){}NodeMonitor::~NodeMonitor(){this->shutdown();//释放资源...操作}void NodeMonitor::ProducerThreadFunc() {while (!shutdown_) { //不断生产std::this_thread::sleep_for(std::chrono::milliseconds(3000));std::string msg = "消息";msg += std::to_string(count_);count_ ++;submitor_->submit(msg);}}NodeMonitor* NodeMonitor::instance(){static NodeMonitor* instance = nullptr;static std::once_flag flag;  std::call_once(flag, [&]{instance = new (std::nothrow) NodeMonitor();});return instance; }void NodeMonitor::ConsumerThreadFunc() {while (!shutdown_) { //不断消费std::this_thread::sleep_for(std::chrono::milliseconds(2000));std::string msg = msg_queue_.pop();//弹出一条消息std::cout << "处理了: " << msg << std::endl;}}void NodeMonitor::start() {init();}void NodeMonitor::shutdown() {shutdown_ = true;}bool NodeMonitor::init() {submitor_.reset(new StateSubmitor(msg_queue_)); //创建submitor//创建生产者,消费者线程并且joinproducer_thread_ = std::thread(&NodeMonitor::ProducerThreadFunc, this);consumer_thread_ = std::thread(&NodeMonitor::ConsumerThreadFunc, this);producer_thread_.join();consumer_thread_.join();return true;}
}int main() {XX::NodeMonitor::instance()->start();return 0;
}

相关文章:

多线程模板应用实现(实践学习笔记)

出处&#xff1a;B站码出名企路 个人笔记&#xff1a;因为是跟着b站的教学视频以及文档初步学习&#xff0c;可能存在诸多的理解有误&#xff0c;对大家仅供借鉴&#xff0c;参考&#xff0c;然后是B站up阳哥的视频&#xff0c;我是跟着他学。大家有兴趣的可以到b站搜索。加油…...

Linux系统中MYSQL重置密码(针对root忘记密码)

⼀ .进⼊MySql配置⽂件中 vi /etc/my.cnf 在最后⼀⾏添加免密码登陆: skip-grant-tables :wq 保存退出 ⼆.重启MySql service mysql restart 或 systemctl restart mysqld.service 三. 登陆数据库 mysql -uroot -p 让输⼊密码直接回⻋就可以 四.修改MySql密码 use mysql…...

蓝桥杯基础知识1 字母大小写转换

蓝桥杯基础知识1 字母大小写转换 isalpha()判断一个字符是否为字母。 isalnum()判断一个字符是否为十进制数字字符或者字母&#xff0c;是否属于a~ z或A~ Z或0~9。 isdigit() 判断一个字符是否是十进制数字字符。十进制数字是&#xff1a;0 1 2 3 4 5 6 7 8 9 isalnum()和isdig…...

攀登者1 - 华为OD统一考试

OD统一考试 分值: 100分 题解: Java / Python / C++ 题目描述 攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如:[0,1,2,4,3,1,0,0,1,2,3,1,2,1,0],代表如下…...

通信原理期末复习——基础小题汇总(二)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…...

代码随想录刷题第四十二天| 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集

代码随想录刷题第四十二天 今天是0-1背包问题&#xff0c;掌握了套路就不难了~~~ 0-1背包问题理论基础&#xff08;二维数组篇&#xff09;卡码网第46题 题目思路&#xff1a; 代码实现&#xff1a; input_line input() # 读取一行输入 mn input_line.split() m, n int…...

前端开发加速器:十个VSCode插件精选

前端开发是一个不断发展的领域&#xff0c;随着技术的进步&#xff0c;工具也在不断更新。Visual Studio Code&#xff08;VSCode&#xff09;是前端开发者广泛使用的编辑器之一&#xff0c;得益于其强大的插件系统&#xff0c;可以帮助开发者提升工作效率。以下是十个对于前端…...

剑指offer面试题3 二维数组中的查找

考察点&#xff1a; 考察数据结构二维数组知识点&#xff1a; 1.java中的数据类型分为基本类型和引用类型&#xff0c;数组属于引用类型&#xff0c;引用类型的变量中存储的是地址&#xff0c;该地址指向内存中的某个对象&#xff0c;参考c中的指针。2.一维数组定义&#xff0c…...

【2023年中国高校大数据挑战赛 】赛题 B DNA 存储中的序列聚类与比对 Python实现

【2023年中国高校大数据挑战赛 】赛题 B DNA 存储中的序列聚类与比对 Python实现 更新时间&#xff1a;2023-12-29 1 题目 赛题 B DNA 存储中的序列聚类与比对 近年来&#xff0c;随着新互联网设备的大量涌入和对其服务需求的指数级增长&#xff0c;越来越多的数据信息被产…...

力扣383.赎金信 -- 哈希表

思路&#xff1a;记录magazine每个字符个数&#xff0c;然后记录ransomNote每个字符&#xff08;每有一个减1&#xff09;&#xff0c;假如出现<0的情况说明ransomnode有字符的个数超过了magazine则无法构成&#xff0c;否则可以构成 代码&#xff1a; class Solution { pu…...

GeoServer发布地图服务(WMS、WFS)

文章目录 1. 概述2. 矢量数据源3. 栅格数据源 1. 概述 我们知道将GIS数据大致分成矢量数据和栅格数据&#xff08;地形和三维模型都是兼具矢量和栅格数据的特性&#xff09;。但是如果用来Web环境中&#xff0c;那么使用图片这个栅格形式的数据载体无疑是最为方便的&#xff0…...

C语言——结构体

一、结构体的创建 1、定义 在 C 语言中&#xff0c;结构体是一种自定义的数据类型&#xff0c;它允许将不同类型的数据项组合成一个单一实体。这在组织复杂数据时非常有用&#xff0c;因为它可以将有逻辑关系的数据组合在一起。结构体是一些值的集合&#xff0c;这些值是结构…...

基于多反应堆的高并发服务器【C/C++/Reactor】(中)Buffer的创建和销毁、扩容、写入数据

TcpConnection:封装的就是建立连接之后得到的用于通信的文件描述符&#xff0c;然后基于这个文件描述符&#xff0c;在发送数据的时候&#xff0c;需要把数据先写入到一块内存里边&#xff0c;然后再把这块内存里边的数据发送给客户端&#xff0c;除了发送数据&#xff0c;剩下…...

【Linux】常用的基本命令指令①

前言&#xff1a;从今天开始&#xff0c;我们逐步的学习Linux中的内容&#xff0c;和一些网络的基本概念&#xff0c;各位一起努力呐&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &#x1f448; &#x1f4af;代码…...

活动运营常用的ChatGPT通用提示词模板

活动目标确定&#xff1a;如何明确活动的目标&#xff0c;确保活动策划与执行的方向性&#xff1f; 活动主题选择&#xff1a;如何选择吸引人的活动主题&#xff0c;提高用户的参与度和兴趣&#xff1f; 活动形式策划&#xff1a;如何根据活动目标和主题&#xff0c;选择适合…...

SpringBoot 中实现订单30分钟自动取消的策略

简介 在电商和其他涉及到在线支付的应用中&#xff0c;通常需要实现一个功能&#xff1a;如果用户在生成订单后的一定时间内未完成支付&#xff0c;系统将自动取消该订单。 本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案&#xff0c;并提供实例…...

像专家一样使用TypeScript映射类型

掌握TypeScript的映射类型&#xff0c;了解TypeScript内置的实用类型是如何工作的。 您是否使用过Partial、Required、Readonly和Pick实用程序类型? 你知道他们内部是怎么运作的吗? 如果您想彻底掌握它们并创建自己的实用程序类型&#xff0c;那么不要错过本文所涵盖的内容。…...

Golang 结构体

前言 在 Go 语言中&#xff0c;结构体&#xff08;struct&#xff09;是一种自定义的数据类型&#xff0c;将多个不同类型的字段&#xff08;fields&#xff09;组合在一起 结构体通常用于模拟真实世界对象的属性和行为 定义结构体 可以使用 type 关键字和 struct 关键字来定…...

服务器运行状况监控工具

服务器运行状况监视提供了每个服务器状态和性能的广泛概述&#xff0c;通过监控服务器指标&#xff0c;如 CPU 使用率、内存消耗、I/O、磁盘使用率、进程等&#xff0c;服务器运行状况监控可以避免服务器停机。 服务器性能监控指标 服务器是网络中最重要的组件之一&#xff0…...

2022年全国职业院校技能大赛软件测试赛题卷②—自动化测试解析报告(含术语)

2022年全国职业院校技能大赛软件测试任务四 自动化测试 目录 第一题:按照以下步骤在PyCharm中进行自动化测试脚本编写,并执行脚本。...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

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

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

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...