muduo网络库剖析——事件循环线程池EventLoopThreadPool类

muduo网络库剖析——线程Thread类

  • 前情
    • 从muduo到my_muduo
  • 概要
  • 框架与细节
    • 成员
    • 函数
    • 使用方法
  • 源码
  • 结尾

前情

从muduo到my_muduo

作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足;而作为学习者,我们需要抽取其中的精华进行简要实现,这要求我们足够了解muduo库。

做项目 = 模仿 + 修改,不要担心自己学了也不会写怎么办,重要的是积累,学到了这些方法,如果下次在遇到通用需求的时候你能够回想起之前的解决方法就够了。送上一段话!

在这里插入图片描述

概要

对于一个one loop one thread,我们有EventLoopThread类,对于多个one loop one thread,我们需要用一个EventLoopThreadPool事先去创建好这个pool。像线程池那样,这样的好处就是存取的时候比较方便,开销更小。

框架与细节

成员

在这里插入图片描述
在几个loop,有一个mainLoop和其他的subLoop。由mainloop来创建其他的subloop。因此,我们在EventLoopThreadPool中只留下了baseLoop_,也就是mainLoop。以及它的名字,thread的数量以及对应数量下的EventLoopThread表。和对应数量下的EventLoop表。另外,对于多个EventLoopThread,是采用轮询的方式,因此还需要一个next_记录mainLoop后一个loop是哪个。

函数

首先是EventLoopThreadPool的构造函数和析构函数。
在这里插入图片描述
对于构造函数,传入参数是mainloop指针,以及对应线程的名字。此时因为没有初始化mainloop,所以传入的线程数量参数也是0。next也初始化为0。

在这里插入图片描述
对于EventLoopThreadPool中的start方法,目标是创建EventLoopThread表中的所有EventLoopThread,并启动所有的loop,相应的EventLoopThread和loop也需要存入到对应的数据结构中,如果没有subLoop,那只能启动mainLoop了。但是在正常情况下应该是启动subLoop,因为mainloop除了处理自己的循环事务之外,对于新的连接它还需要监听,对于新的subloop他还需要创建,因此想要负载均衡,最好是调用subloop来分摊mainloop的压力。而numthread_一开始是0,所以一开始是启动mainloop,而后在mainloop创建新的subloop时,对应的numthread_应该也会增加。因此对于私有的numthread_成员,我们要提供一个公有函数的接口在这里插入图片描述
在这里插入图片描述
对于在EventLoopThreadPool的数据创建好之后,我们需要提供给用户轮询整个EventLoopThreadPool的接口,即getNextLoop函数。在这个函数中,我们需要从mainloop开始轮询。所以先使用一个EventLoop指针,指向mainloop.通过我们的EventLoop表,进行轮询,在轮询的时候注意next指针的变化。并需要记住轮询是尾部和头部的衔接,最后返回next loop。这里有个比较关键的点是为什么我们不用EventLoopThread来遍历,而使用EventLoop来遍历。因为EventLoop是我们处理事件循环的功能类,而EventLoopThread主要是事件循环和线程相对应的衔接类,因此基于功能来讲,我们在EventLoopThreadPool需要留下这样一个功能类表,也是我们返回EventLoop的原因。

在这里插入图片描述
最后,还提供了一个获取所有EventLoop的函数接口,有利于我们debug。

使用方法

源码

//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_;
};
//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
EventLoop* EventLoopThreadPool::getNextLoop() {
    EventLoop *loop = baseLoop_;
    // 通过轮询获取下一个处理事件的loop
    if (!loops_.empty())  {
        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_;
    }
}

结尾

以上就是事件循环线程池EventLoopThreadPool类的相关介绍,以及我在进行项目重写的时候遇到的一些问题,和我自己的一些心得体会。发现写博客真的会记录好多你的成长,而且对于一个好的项目,写博客也是证明你确实有过深度思考,并且在之后面试或者工作时遇到同样的问题能够进行复盘的一种有效的手段。所以,希望uu们也可以像我一样,养成写博客的习惯,逐渐脱离菜鸡队列,向大佬前进!!!加油!!!

也希望我能够完成muduo网络库项目的深度学习与重写,并在功能上能够拓展。也希望在完成这个博客系列之后,能够引导想要学习muduo网络库源码的人,更好地探索这篇美丽繁华的土壤。致敬chenshuo大神!!!

鉴于博主只是一名平平无奇的大三学生,没什么项目经验,所以可能很多东西有所疏漏,如果有大神发现了,还劳烦您在评论区留言,我会努力尝试解决问题!

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

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

相关文章

Spring结合工厂模式

学习设计模式&#xff0c;不要进入一个误区生搬硬套&#xff0c;它是一种编程思想&#xff0c;结合实际使用&#xff0c;往往设计模式是混合使用的 工厂模式 核心本质&#xff1a;使用工厂统一管理对象的创建&#xff0c;将调用者跟实现类解耦 我这里使用Spring容器的支持&am…

latent-diffusion model环境配置--我转载的

latent-diffusion model环境配置&#xff0c;这可能是你能够找到的最细的博客了_latent diffusion model 训练 autoencoder-CSDN博客 前言 最近在研究diffusion模型&#xff0c;并对目前最火的stable-diffusion模型很感兴趣&#xff0c;又因为stable-diffusion是一种latent-di…

【QT+QGIS跨平台编译】之十五:【libTiff+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、libTiff介绍二、文件下载三、文件分析四、pro文件五、编译实践一、libTiff介绍 libTiff是一个用于处理TIFF图像文件格式的开源软件库。 TIFF(Tagged Image File Format)是一种灵活且广泛支持的图像文件格式,常用于存储照片和其他高质量图像。libTiff提供了一套…

Qt QPlainTextEdit高亮显示当前行

Qt QPlainTextEdit高亮显示当前行 文章目录 Qt QPlainTextEdit高亮显示当前行摘要错误的代码正确的代码QTextEdit::ExtraSelection 关键字&#xff1a; Qt、 QPlainTextEdit、 QTextBlock、 ExtraSelection、 GPT 摘要 今天要在说一下GPT&#xff0c;当下如果你还不会用G…

STM32读取MPU6050数据并通过角度值控制舵机运动(STM32、GY-521 MPU6050、SG90舵机、MG946舵机)

通过STM32F103C8T6读取MPU6050数据控制舵机运动&#xff08;STM32、GY-521 MPU6050、SG90舵机、MG946舵机&#xff09; 最终现象一、MPU6050数据读取二、舵机控制原理①什么是PWM&#xff1f;②STM32F103C8T6如何生成PWM&#xff1f;③控制舵机需要什么样的PWM波&#xff1f; 三…

qemu调试kernel启动(从第一行汇编开始)

一、背景 大部分qemu调试kernel 都是讲解从start_kernel开始设置断点&#xff0c;然后开启调试&#xff1b; 但是我们熟悉linux启动流程的伙伴肯定知道&#xff0c;在start_kernel之前还有一段汇编&#xff0c;包括初始化页表及mmu等操作&#xff0c; 这部分如何调试呢&#x…

cocos添加节点事件的3种方式

我们以button为例来说明一下cocos怎样为节点添加事件&#xff1a; 直接通过cocos熟悉检查器绑定 添加事件脚本 import { _decorator, Component, Node, input, Input, Button, EventKeyboard } from cc; const { ccclass, property } _decorator;ccclass(Attack) export cla…

【vue】图片加载骨架

一、前言 在网速较低或者网站的服务器宽带只有几MB的情况下&#xff0c;网页中的图片加载时&#xff0c;要么空白&#xff0c;要么像打印机一样一行一行地“扫描”出来&#xff0c;为了提升用户体验&#xff0c;可以给图片标签外加一层骨架。 无骨架 有骨架 二、详细设计 每张…

无人机在三维空间中的转动问题

前提 这篇博客是对最近一个有关无人机拍摄图像项目中所学到的新知识的一个总结&#xff0c;比较杂乱&#xff0c;没有固定的写作顺序。 无人机坐标系旋转问题 上图是无人机坐标系&#xff0c;绕x轴是翻滚(Roll)&#xff0c;绕y轴是俯仰(Pitch)&#xff0c;绕z轴是偏航(Yaw)。…

sqli-labs第一关

1.判断是否存在注入&#xff0c;注入是字符型还是数字型? ?id1 and 11 ?id1 and 12 因为输入and 11与and 12 回显正常&#xff0c;所以该地方不是数字型。 ?id1 ?id1-- 输入单引号后报错&#xff0c;在单引号后添加--恢复正常&#xff0c;说明存在字符注入 2.猜解SQL查…

Spark Exchange节点和Partitioning

​Exchange 在explain时&#xff0c;常看到Exchange节点&#xff0c;这个节点其实就是发生了数据交换 此图片来自于网络截取 BroadcastExchangeExec 主要是用来广播的 ShuffleExchangeExec 里面决定了数据分布的方式和采用哪种shuffle 在这里可以看到好几种不同的分区器 shuf…

Windows11搭建GPU版本PyTorch环境详细过程

Anaconda安装 https://www.anaconda.com/ Anaconda: 中文大蟒蛇&#xff0c;是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。从官网下载Setup&#xff1a;点击安装&#xff0c;之后勾选上可以方便在普通命令行cmd和PowerShell中使用…

聊聊Git合并和变基

一、 Git Merge 合并策略 1.1 Fast-Forward Merge&#xff08;快进式合并&#xff09; //在分支1下操作&#xff0c;会将分支1合并到分支2中 git merge <分支2>最简单的合并算法&#xff0c;它是在一条不分叉的两个分支之间进行合并。快进式合并是默认的合并行为&#…

微信小程序wx.getRealtimeLogManager无法查看log内容

解决方案&#xff1a; 首先&#xff0c;检查在we分析是否启用实时日志&#xff0c;入口如下&#xff1a; 其次&#xff0c;检查基本语法是否正确&#xff0c;参考如下&#xff1a; var logger wx.getRealtimeLogManager() logger.error("error message") 最后&a…

你好,C++对象

你好&#xff0c;对象 面向对象开发对象的定义 类与对象类的定义类的访问限定符及封装类的实例化类对象模型结构体内存对齐规则 this指针this指针的引入 this指针的特性 类的默认成员函数构造函数析构函数拷贝构造函数结语 面向对象开发 对象的定义 对象的含义是指具体的某一…

在docker中安装MQTT教程

网上的好多关于在docker中安装MQTT教程都是错误的不完整的。这篇博客是完整的&#xff0c;实践过的&#xff0c;踩过了很多的坑得来的&#xff0c;欢迎大家享用&#xff01; 1、首先在docker中拉取镜像 docker pull eclipse-mosquitto2、创建配置文件目录 mkdir -p /docker/…

axure如何载入元件库

首先&#xff0c;安装axure后打开 1.打开axure软件后&#xff0c;左侧可以看到一个叫元件库的菜单 2.点击元件库右侧的选项按钮 然后在出现的下拉菜单中点击载入元件库 3.找到自己下载好的元件库&#xff08;Axure元件库合集&#xff09;&#xff0c;双击它就可以载入了 可以看…

Linux:共享内存

文章目录 System V共享内存的原理管理共享内存shmgetshmatshmdtshmctl 共享内存和管道实现进程间同步通信 前面介绍完了匿名管道和命名管道&#xff0c;那么本篇要引入的主题是共享内存 System V 作为进程通信部分的内容&#xff0c;共享内存必然有其存在的意义和价值&#x…

༺༽༾ཊ—Unity之-04-工厂方法模式—ཏ༿༼༻

首先创建一个项目&#xff0c; 在这个初始界面我们需要做一些准备工作&#xff0c; 建基础通用文件夹&#xff0c; 创建一个Plane 重置后 缩放100倍 加一个颜色&#xff0c; 任务&#xff1a;使用工厂方法模式 创建 飞船模型&#xff0c; 首先资源商店下载飞船模型&#xff0c…

mkcert的安装和使用,5分学会在本地开启localhost的https访问方式

mkcert官方仓库地址&#xff1a;https://github.com/FiloSottile/mkcert#installation mkcert 是一个简单的工具&#xff0c;用于制作本地信任的开发证书。它不需要配置。 简化我们在本地搭建 https 环境的复杂性&#xff0c;无需操作繁杂的 openssl 实现自签证书了&#xff…