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

出处: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_;
            //queue
            std::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
        //创建生产者,消费者线程并且join
        producer_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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

webpack的性能优化(一)——分包优化

1.什么是分包&#xff1f;为什么要分包&#xff1f; 默认情况下&#xff0c;Webpack 会将所有代码构建成一个单独的包&#xff0c;这在小型项目通常不会有明显的性能问题&#xff0c;但伴随着项目的推进&#xff0c;包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这…

【Linux】进程信号——进程信号的概念和介绍、产生信号、四种产生信号方式、阻塞信号、捕捉信号、阻塞和捕捉信号的函数

文章目录 进程信号1.进程信号的概念和介绍2.产生信号2.1通过终端按键产生信号2.2 调用系统函数向进程发信号2.3 由软件条件产生信号2.4硬件异常产生信号 3.阻塞信号3.1信号在内核中的表示3.2信号集操作函数3.3sigprocmask 4.捕捉信号4.1内核如何实现信号的捕捉4.2 sigaction 进…

【AI视野·今日Robot 机器人论文速览 第七十一期】Fri, 5 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Fri, 5 Jan 2024 Totally 11 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Machine Learning in Robotic Ultrasound Imaging: Challenges and Perspectives Authors Yuan Bi, Zhongliang Jiang, Felix D…

线性代数 --- 矩阵行列式的性质

Determinant det A|A| 矩阵的行列式是一个数&#xff0c;这个数能够反应一些关于矩阵的信息。行列式只对方阵有效。 若矩阵A为&#xff1a; 则A的行列式为&#xff1a; 性质1&#xff1a; 单位矩阵的行列式等于1 性质2&#xff1a;行与行之间的交换会改变det的正负号 以2x2单位…

Mybatis入门源码二:sql执行

后面开始分析sql执行的源码流程也就是这一部分 一、factory.openSession() 重点关注configuration.newExecutor这个方法&#xff0c;获取事务处理器比较简单&#xff0c;就是获取一个jdbc的事务管理器。 这个方法通过传入的执行器类型来创建不同的执行器&#xff0c;有simp…

x-cmd pkg | trdsql - 能对 CSV、LTSV、JSON 和 TBLN 执行 SQL 查询的工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trdsql 是一个使用 sql 作为 DSL 的强大工具: 采用 SQL 对 CSV、LTSV、JSON 和 TBLN 文件执行查询与 MySQL&#xff0c;Postgresql&#xff0c;Sqlite 的 Driver 协同&#xff0c;可以实现对应数据库的表与文件的 JO…

安全基础~信息搜集3

文章目录 知识补充APP信息搜集php开发学习理解漏洞 知识补充 端口渗透总结 python Crypto报错&#xff1a;https://blog.csdn.net/five3/article/details/86160683 APP信息搜集 1. AppInfoScanner 移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具 使用教程 演示&…

超维空间M1无人机使用说明书——21、基于opencv的人脸识别

引言&#xff1a;M1型号无人机不仅提供了yolo进行物体识别&#xff0c;也增加了基于opencv的人脸识别功能包&#xff0c;仅需要启动摄像头和识别节点即可 链接: 源码链接 一、一键启动摄像头和人脸识别节点 roslaunch robot_bringup bringup_face_detect.launch无报错&#…

解决ImportError: Failed to import test module: sys.__init__

解决ImportError: Failed to import test module: sys.init 背景 学习通过文件夹执行测试脚本时&#xff0c;出现了错误&#xff1a;ImportError: Failed to import test module: sys.__init__ 解决过程 根据报错信息&#xff1a;sys is not a package大胆猜测可能是文件名…

爬虫-1-请求和响应

#无以规矩&#xff0c;不成方圆(&#xff89;_ _)&#xff89; <(_ _)> 请求和响应 案例实现

STLink下不了程序的解决办法

目录 1.检查物理接线是否正确 2.检查工程中用的引脚与这两个引脚是否有冲突 3.其次查看HAL_MspInit函数中是否使能SWJ 1.检查物理接线是否正确 2.检查工程中用的引脚与这两个引脚是否有冲突 stm32 swdio和swdclk引脚分别与stm32的PA13&#xff0c;PA14引脚相连 3.其次查看HA…

C++模板——(1)模板的概念

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 创造机会的人是勇者&#xff0c;等待机…

构建网络信息安全的中国方案 - 国密SSL协议介绍以及国密Nginx服务器部署

国密SSL协议 国密SSL协议指的是采用国密算法&#xff0c;符合国密标准的安全传输协议。简而言之&#xff0c;国密SSL就是SSL/TLS协议的国密版本。TLS协议定义有三个版本号&#xff0c;为0x0301、0x0302、0x0303&#xff0c;分别对应TLS 1.0、1.1、1.2。国密SSL为了避免冲突&am…

Spanner on a modern columnar storage engine 中文翻译

文章目录 0. 摘要1. 存储引擎2. 存储引擎迁移的挑战2.1 可靠性、可用性和数据完整性2.2 性能和成本2.3 复杂性 3. 迁移可靠性的系统原则方法3.1 可靠性原则和自动化架构3.2 迁移方案和按周迁移3.3 客户 部署感知 调度3.4 管理可靠性、可用性和性能 4. 项目管理和驱动指标概括 0…

在 Linux 中开启 Flask 项目持续运行

在 Linux 中开启 Flask 项目持续运行 在部署 Flask 项目时&#xff0c;情况往往并不是那么理想。默认情况下&#xff0c;关闭 SSH 终端后&#xff0c;Flask 服务就停止了。这时&#xff0c;您需要找到一种方法在 Linux 服务器上实现持续运行 Flask 项目&#xff0c;并在服务器…

【AI视野·今日Robot 机器人论文速览 第六十九期】Wed, 3 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Wed, 3 Jan 2024 Totally 5 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers NID-SLAM: Neural Implicit Representation-based RGB-D SLAM in dynamic environments Authors Ziheng Xu, Jianwei Niu, Qingf…

Unity 一文掌握使用AddListener方法为组件事件添加监听器的方法

在Unity中&#xff0c;很多组件都带有事件&#xff0c;比如: Button组件&#xff1a;onClick() Toggle组件&#xff1a;On Value Changed(Boolean) Dropdown组件&#xff1a;On Value Changed(Int32) InputField组件&#xff1a;On Value Changed(String)、On End Edit(Stri…

(源码解析)mybatis调用链之XMLMapperBuilder解析Mapper

创建XMLMapperBuilder对象 XMLMapperBuilder mapperParser new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); XMLMapperBuilder继承于BaseBuilder public XMLMapperBuilder(InputStream inputStream, Configuration configu…

《GreenPlum系列》GreenPlum详细入门教程01-GreenPlum介绍

文章目录 第一章 GreenPlum介绍1.MPP架构介绍2.GreenPlum介绍3.GreenPlum数据库架构4.GreenPlum数据库优缺点 GreenPlum&#xff1a;https://cn.greenplum.org/ 第一章 GreenPlum介绍 1.MPP架构介绍 MPP是Massively Parallel Processing的缩写&#xff0c;也就是大规模并行处…

客服系统实现类似发送位置功能

地图选点组件 地图选点组件&#xff0c;类似微信中的“发送位置”功能&#xff0c;该组件可以让用户快速、准确地选择并确认自己的当前位置&#xff0c;并将相关位置信息回传给开发者。 调用示例 调用方式一 通过iframe内嵌调用&#xff0c;地图选点组件的页面会根据开发者设…
最新文章