重写muduo之Thread、EventLoopThread、EventLoopThreadPool

目录

1、概述

2、Thread

2.1 Thread.h

3、EventLoopThread

3.1 EventLoopThread.h

3.2  EventLoopThread.cc

4、 EventLoopThreadPool

4.1 EventLoopThreadPool.h

4.2 EventLoopThreadPool.cc


1、概述

管理事件循环线程的调度的

打包了一个EventLoop和线程,绑定了一个loop跟thread,让这个loop运行在这个thread上,在这个thread里面创建一个loop(one loop per thread)

底层封装的线程

2、Thread

2.1 Thread.h

#pragma once

#include "noncopyable.h"

#include <functional>
#include <thread>
#include <memory>
#include <string>
#include <atomic>

class Thread:noncopyable
{
public:
    using ThreadFunc=std::function<void()>;//线程函数的函数类型  绑定器和函数对象,就可以传参 

    explicit Thread(ThreadFunc,const std::string& name=std::string());//构造函数
    ~Thread();

    void start();//启动当前线程 
    void join();//当前线程等待其他线程完了再运行下去 

    bool started()const {return started_;}
    pid_t tid()const{return tid_;}
    const std::string& name()const{return name_;}

    static int numCreated(){return numCreated_;}
private:
    void setDefaultName();//给线程设置默认的名称
    bool started_;//启动当前线程 
    bool joined_;//当前线程等待其他线程完了再运行下去 
    std::shared_ptr<std::thread> thread_;//自己来掌控线程对象产生的时机
    pid_t tid_;
    ThreadFunc func_;//存储线程函数 
    std::string name_;//调试的时候打印 
    static std::atomic_int numCreated_;//对线程数量计数 
};

 我们使用C++结合lambda表达式 的方法来实现,非常方便。

3、EventLoopThread

3.1 EventLoopThread.h

#pragma once

#include "noncopyable.h"
#include "Thread.h"

#include <functional>
#include <mutex>
#include <condition_variable>
#include <string>

class EventLoop;

class EventLoopThread:noncopyable
{
public:
    using ThreadInitCallback=std::function<void(EventLoop*)>;

    EventLoopThread(const ThreadInitCallback& cb=ThreadInitCallback(), //线程初始化的回调 
        const std::string& name=std::string());
    ~EventLoopThread();

    EventLoop* startLoop();//开启循环 
private:
    void threadFunc();//线程函数,创建loop 

    EventLoop* loop_;
    bool exiting_;//是否退出循环
    Thread thread_;
    std::mutex mutex_;
    std::condition_variable cond_;
    ThreadInitCallback callback_;//初始化操作 
};

3.2  EventLoopThread.cc

#include "EventLoopThread.h"
#include "EventLoop.h"


EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, //线程初始化的回调 
        const std::string& name)
        :loop_(nullptr)
        ,exiting_(false)
        ,thread_(std::bind(&EventLoopThread::threadFunc,this),name)//绑定回调函数
        ,mutex_()
        ,cond_()
        ,callback_(cb)
        {

        }
EventLoopThread::~EventLoopThread()
{
    exiting_=true;
    if(loop_!=nullptr)
    {
        loop_->quit();
        thread_.join();
    }
}

EventLoop* EventLoopThread::startLoop()//开启循环 
{
    thread_.start();//启动底层的新线程
	//启动后执行的是EventLoopThread::threadFunc

    EventLoop* loop=nullptr;
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while(loop_==nullptr)//loop指针还没有初始化
        {
            cond_.wait(lock);挂起,等待
        }
        loop=loop_;
    }
    return loop;
}

//下面这个方法,是在单独的新线程里面运行的
void EventLoopThread::threadFunc()//线程函数,创建loop 
{
    EventLoop loop;//创建一个独立的eventloop,和上面的线程是一一对应的,one loop per thread

    if(callback_)//如果有回调
    {
        callback_(&loop);//绑定loop做一些事情
    }

    {
        std::unique_lock<std::mutex> lock(mutex_);
        loop_=&loop;//就是运行在这个线程的loop对象,将这个对象初始化好之后(loop指针指向loop对象),才能唤醒(通知)
        cond_.notify_one();//唤醒1个线程,被唤醒后去访问loop指针
    }
    loop.loop();//EventLoop loop=>Poller.poll
    std::unique_lock<std::mutex> lock(mutex_);
    loop_=nullptr;
}

4、 EventLoopThreadPool

这个很明显,是池的概念。是一个事件线程池,管理eventloop,eventloop绑定的就是一个线程。

用户最开始创建的loop,对应的是一个线程

4.1 EventLoopThreadPool.h

#pragma once
#include "noncopyable.h"

#include <functional>
#include <string>
#include <vector>
#include <memory>

class EventLoop;
class EventLoopThread;

class EventLoopThreadPool:noncopyable
{
public:
    using ThreadInitCallback=std::function<void(EventLoop*)>;

    EventLoopThreadPool(EventLoop* baseLoop,const std::string& nameArg);
    ~EventLoopThreadPool();

    void setThreadNum(int numThreads){numThreads_=numThreads;}

    void start(const ThreadInitCallback& cb=ThreadInitCallback());

    //如果工作在多线程中,baseloop_默认以轮询的方式分配channel给subloop
    EventLoop* getNextLoop();

    std::vector<EventLoop*> getAllLoops();

    bool started()const{return started_;}
    const std::string name() const{return name_;}
private:
    EventLoop* baseLoop_;//EventLoop loop;
    std::string name_;
    bool started_;
    int numThreads_;
    int next_;
    std::vector<std::unique_ptr<EventLoopThread>> threads_;
    std::vector<EventLoop*> loops_;
};

4.2 EventLoopThreadPool.cc

#include "EventLoopThreadPool.h"
#include "EventLoopThread.h"

#include <memory>

 EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop,const std::string& nameArg)
    :baseLoop_(baseLoop)
    ,name_(nameArg)
    ,started_(false)
    ,numThreads_(0)
    ,next_(0)
 {}
EventLoopThreadPool::~EventLoopThreadPool()
{}

void EventLoopThreadPool::start(const ThreadInitCallback& cb)
{
    started_=true;

    for(int i=0;i<numThreads_;i++)
    {
        char buf[name_.size()+32];
        snprintf(buf,sizeof buf,"%s%d",name_.c_str(),i);
        EventLoopThread* t=new EventLoopThread(cb,buf);
        threads_.push_back(std::unique_ptr<EventLoopThread>(t));
        loops_.push_back(t->startLoop());//底层创建线程,绑定一个新的EventLoop,并返回该loop的地址
    }

    //整个服务端只有一个线程,运行着baseloop
    if(numThreads_==0&&cb)
    {
        cb(baseLoop_);
    }
}

//如果工作在多线程中,baseloop_默认以轮询的方式分配channel给subloop
//通过轮询的方式从子线程中取loop(循环)
//IO线程  baseloop  用作处理用户的连接事件
//工作线程  新创建的loop  用于处理用户的读写事件
EventLoop* EventLoopThreadPool::getNextLoop()
{
    EventLoop* loop=baseLoop_;

    if(!loops_.empty())//通过轮询获取下一个处理事件的loop
    {
        loop=loops_[next_];
        next_++;
        if(next_>=loops_.size())
        {
            next_=0;
        }
    }
    return loop;
}

std::vector<EventLoop*> EventLoopThreadPool::getAllLoops()
{
    if(loops_.empty())
    {
        return std::vector<EventLoop*>(1,baseLoop_);
    }
    else
    {
        loops_;
    }
}

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

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

相关文章

在ubuntu虚拟机中手动安装VMware Tools(VMware Workstation 17 player)

可参考官方文档&#xff1a;在 Linux 虚拟机中手动安装 VMware Tools 以下列出我在安装过程中遇见的问题&#xff1a; 1、“安装VMware Tools”选项为灰&#xff0c;无法选中 原因是VMware Tools的安装包镜像在Player的安装目录下&#xff0c;需要在虚拟机启动的时候加载这个…

【数字经济】上市公司供应链数字化数据(2000-2022)

数据来源&#xff1a; 时间跨度&#xff1a;2000-2022年 数据范围&#xff1a;各上市企业 数据指标&#xff1a; 样例数据&#xff1a; 参考文献&#xff1a;[1]刘海建,胡化广,张树山,等.供应链数字化的绿色创新效应[J].财经研究,2023,49(03):4-18. 下载链接&#xff1a;https:…

关系型数据库MySQL开发要点之多表查询2024详解

多表查询 准备测试数据 -- 部门管理 create table tb_dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not null unique comment 部门名称,create_time datetime not null comment 创建时间,update_time datetime not null comment 修改时…

图神经网络综述和学习路径

应用邻域 应用举例 应用层面&#xff08;节点&#xff0c;连接&#xff0c;子图&#xff0c;全图&#xff09; 概念区别 图神经网络本质上解决了表示学习的问题 可以把神经网络看作一个黑箱&#xff0c;图中的f函数 困难与挑战 现代的深度学习&#xff0c;如何把图输入到神经…

Clion STM32CubeMX 项目

系列文章目录 前言 最后修改 2024 年 4 月 16 日 操作系统&#xff1a;Windows / Linux / macOS 所需工具 STM32CubeMX、GNU ARM 工具链 项目格式&#xff1a; CMake 兼容配置&#xff1a; OpenOCD 运行与调试/嵌入式 GDB 服务器 对于以 STM32 板卡为目标的嵌入式项目&#xf…

QX-mini51单片机学习-----(3)流水灯

目录 1宏定义 2函数的定义 3延时函数 4标准库函数中的循环移位函数 5循环移位函数与左移和右移运算符的区别 6实例 7keil中DeBug的用法 1宏定义 是预处理语句不需要分号 #define uchar unsigned char//此时uchar代替unsigned char typedef是关键字 后面是接分号…

【Linux】线程的内核级理解详谈页表以及虚拟地址到物理地址之间的转化

一、线程的概念 对于进程来说&#xff0c;进程创建时间和空间成本较高&#xff0c;因为进程是承担分配系统资源的基本实体&#xff0c;所以线程的出现就成为了必然。Linux线程与进程非常相似&#xff0c;Linux设计者在设计之初觉得如果再为线程设计数据结构和调度算法就会使整个…

java--io流(一)

1. 前置知识 字符集是什么&#xff1f; 字符集&#xff08;Character Set&#xff09;是一组字符的集合&#xff0c;它定义了可以在计算机系统中使用的所有字符。字符集可以包括字母、数字、标点符号、控制字符、图形符号等。字符集使得计算机能够存储、处理和显示各种语言和…

idea 项目 修改项目文件名 教程

文章目录 目录 文章目录 修改流程 小结 概要流程技术细节小结 概要 原项目名 修改流程 关掉当前项目的idea页面 修改之后的文件名 重新打开idea。选择项目打开项目页面 技术细节 出现下面这个问题&#xff0c;可以参考作者新的一编文章idea开发工具 项目使用Spring框架开发解…

【智能楼宇秘籍】一网关多协议无缝对接BACnet+OPC+MQTT

在繁华的都市中心&#xff0c;一座崭新的大型商业综合体拔地而起&#xff0c;集购物、餐饮、娱乐、办公于一体&#xff0c;是现代城市生活的缩影。然而&#xff0c;这座综合体的幕后英雄——一套高度集成的楼宇自动化系统&#xff0c;正是依靠多功能协议网关&#xff0c;实现了…

《从零开始,搭建一个简单的UVM验证平台》实操

最近的工作中需要用UVM平台去仿真软件同事写的C程序&#xff0c;虽然只要用EDA同事已经搭好的UVM平台稍微改改就行&#xff0c;但对于我这种从未接触过UVM甚至都没用过System Verilog的纯FPGA工程师来说还是很有难度的&#xff0c;因为我对这方面一点概念都没有。 基于此&…

一文盘点 Partisia Blockchain 生态 4 月市场进展

Partisia Blockchain 是一个以高迸发、隐私、高度可互操作性、可拓展为特性的 Layer1 网络。通过将 MPC 技术方案引入到区块链系统中&#xff0c;以零知识证明&#xff08;ZK&#xff09;技术和多方计算&#xff08;MPC&#xff09;为基础&#xff0c;共同保障在不影响网络完整…

redis--安装

简介 官网&#xff1a;RedisInsight - The Best Redis GUI 各个版本官网下载地址&#xff1a;http://download.redis.io/releases/ Redis和Memcached是非关系型数据库也称为NoSQL数据库&#xff0c;MySQL、Mariadb、SQL Server、PostgreSQL Oracle 数据库属于关系型数据 应用…

17.接口自动化学习-日志

1.日志输出渠道 &#xff08;1&#xff09;文件格式 xx.log &#xff08;2&#xff09;控制台输出 2.日志级别 debug<info<warnning<error<critical 3.代码实现 from utils.handle_path import log_path import logging import datetime def logger(fileLogTr…

rocketMQ-常用知识点

1、RocketMQ有什么作用&#xff1f; 1、应用解耦 系统的耦合性越高&#xff0c;容错性就越低。以电商应用为例&#xff0c;用户创建订单后&#xff0c;如果耦合调用库存系统、物流系统、支付系统&#xff0c;任何一个子系统出了故障或者因为升级等原因暂时不可用&#xff0c;都…

多线程【阻塞队列】(生产者消费者模型代码实现)

阻塞队列 解耦合削峰填谷生产者消费者模型&#xff1a; 解耦合 削峰填谷 生产者消费者模型&#xff1a; 正常来说&#xff0c;wait通过notify唤醒&#xff0c;其他线程调用了take,在take的最后一步进行notify. package thread; class MyBlockingQueue{private String [] data…

OpenCV 入门(二)—— 车牌定位

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

存储虚拟化概述

目录 1. 存储体系架构 2. 存储设备层虚拟化 3. 块聚合层虚拟化 3.1. 块聚合层虚拟化实现方式 3.2. 块聚合层虚拟化分类 3.3. 块聚合层虚拟化技术 4. 文件/记录层的存储虚拟化 存储虚拟化是一种将存储系统的内部功能从应用、主机或者网络资源中抽象、隐藏或者隔离的技术&…

事业单位向媒体投稿发文章上级领导交给了我投稿方法

作为一名事业单位的普通职员,负责信息宣传工作,我见证了从传统投稿方式到智能化转型的全过程,这段旅程既是一次挑战,也是一次宝贵的成长。回想起初涉此领域的日子,那些通过邮箱投稿的时光,至今仍然历历在目,其中的酸甜苦辣,构成了我职业生涯中一段难忘的经历。 邮箱投稿:费时费…

06-beanFactoryPostProcessor的执行

文章目录 invokeBeanFactoryPostProcessors(beanFactory)invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);invokeBeanFactoryPostProcessors(regularPostProc…
最新文章