[muduo网络库]——muduo库EventLoopThreadPool类(剖析muduo网络库核心部分、设计思想)

本文主要是介绍[muduo网络库]——muduo库EventLoopThreadPool类(剖析muduo网络库核心部分、设计思想),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接着之前我们[muduo网络库]——muduo库EventLoopThread类(剖析muduo网络库核心部分、设计思想),我们接下来继续看muduo库中的EventLoopThreadPool类,它和Thread以及EventLoopThread类息息相关。

EventLoopThreadPool类

事件循环线程池,管理所有客户端连接,每个线程都有唯一一个事件循环,可以调用setThreadNum设置线程的数目。线程池中每一个线程都有一个自己的EventLoop,而每一个EventLoop底层都是一个epoll,它利用了自身的epoll在没有事件的时候阻塞住,在有事件发生的时候,epoll监听到了事件就会去处理事件。

重要成员变量

EventLoop *baseLoop_;  //主线程loop
std::string name_;
bool started_; //标记当前状态 即IO线程是否开始运行
int numThreads_; //线程池中线程的数量
int next_;  //负载均衡用
std::vector<std::unique_ptr<EventLoopThread>> threads_;//创建事件的线程
std::vector<EventLoop*> loops_; //事件线程里面EventLoop的指针,每个EventLoopThread线程对应的EventLoop保存在loops_中
  • 具体含义如注释所示

重要成员函数

  • 设置底层线程的数量,状态,名字
void setThreadNum(int numThreads) { numThreads_ = numThreads;}
bool started() const { return started_;}
const std::string name() const { return name_;}
  • 启动线程池,实际上创建numThreads个线程,并让每个eventloopthread调用startLoop()
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()); }//整个服务端只有一个线程,运行着baseloopif (numThreads_ == 0 && cb){cb(baseLoop_);//执行}
}
  1. 设置当前状态为true,根据需要的线程数numThreads_,创建线程
  2. 在for循环中,先创建一个EventLoopThread对象,构造线程池内线程集合
  3. 调用EventLoopThread::startLoop(),创建线程,绑定一个新的EventLoop,并返回loop地址,放入loops_中,loops_是一个std::vector<EventLoop*>类型,把每个EventLoopThread线程对应的EventLoop保存在loops_中。
  4. 如果没有其他线程,只有主线程的话,直接调用callback
  • 以轮询的方式分配channel给subloop
EventLoop* EventLoopThreadPool::getNextLoop()
{EventLoop* loop = baseLoop_;if(!loops_.empty())// 通过轮询,获取下一个处理事件的loop{loop = loops_[next_];++next_;if(next_ >= loops_.size()){next_ = 0;}}return loop;
}

注意: 在TcpServer::newConnection 会通过EventLoop *ioLoop = threadPool_->getNextLoop();初始时loop被赋值为baseLoop_,也就是主线程的loop,如果我们设置子线程为零的话程序也可正常运行,也就是说,getNextLoop的实现意味着muduo是支持单线程的;
如果loops_不为空,loop = loops_[next_],ioLoop就得到了一个subloop

花了很长时间在思考这个cb(baseLoop_)是为什么呢?(个人理解,如果大家觉得有错,麻烦指正)
  1. 在TcpServer::start(),启动IO线程池 threadPool_->start(threadInitCallback_); cb=threadInitCallback_;
  2. 来到了EventLoopThreadPool::start()中,创建一个EventLoopThread对象EventLoopThread *t =new EventLoopThread(cb,buf); ,在这里callback_(cb),先把cb给到了callback_
  3. 接着EventLoopThread::startLoop(),中调用 Thread::start()
  4. 在EventLoopThread的构造函数中,thread_(std::bind(&EventLoopThread::threadFunc,this),name),绑定了threadFunc,在Thread构造函数中func_(std::move(func)),所以会调用EventLoopThread::threadFunc()函数,这里创建了一个EventLoop,并给了callback_;
  5. 所以如果有其他线程,就创建一个loop给回去,没有就会给回去baseLoop_;
  6. EventLoopThreadPool里面的loops_就存了每个EventLoopThread线程对应的EventLoop;
  7. 然后loop_->runInLoop(std::bind(&Acceptor::listen,acceptor_.get()));

代码地址:https://github.com/Cheeron955/mymuduo/tree/master

好了~ 关于muduo库的EventLoopThreadPool类就剖析到这里,与它相关的Thread,EventLoopThread也都完结了,这部分其实有一点不知所云,希望大家发现错误能够批评指正。最后,除去TcpServer,我们就剩下InetAddress类了,下一篇我们来剖析InetAddress类,然后就从整个服务器流程来讲TcpServer ~ 我们下一节见 ~~

这篇关于[muduo网络库]——muduo库EventLoopThreadPool类(剖析muduo网络库核心部分、设计思想)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/991391

相关文章

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

详解MySQL中DISTINCT去重的核心注意事项

《详解MySQL中DISTINCT去重的核心注意事项》为了实现查询不重复的数据,MySQL提供了DISTINCT关键字,它的主要作用就是对数据表中一个或多个字段重复的数据进行过滤,只返回其中的一条数据... 目录DISTINCT 六大注意事项1. 作用范围:所有 SELECT 字段2. NULL 值的特殊处

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

java中Optional的核心用法和最佳实践

《java中Optional的核心用法和最佳实践》Java8中Optional用于处理可能为null的值,减少空指针异常,:本文主要介绍java中Optional核心用法和最佳实践的相关资料,文中... 目录前言1. 创建 Optional 对象1.1 常规创建方式2. 访问 Optional 中的值2.1

Linux网络配置之网桥和虚拟网络的配置指南

《Linux网络配置之网桥和虚拟网络的配置指南》这篇文章主要为大家详细介绍了Linux中配置网桥和虚拟网络的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、网桥的配置在linux系统中配置一个新的网桥主要涉及以下几个步骤:1.为yum仓库做准备,安装组件epel-re

python如何下载网络文件到本地指定文件夹

《python如何下载网络文件到本地指定文件夹》这篇文章主要为大家详细介绍了python如何实现下载网络文件到本地指定文件夹,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...  在python中下载文件到本地指定文件夹可以通过以下步骤实现,使用requests库处理HTTP请求,并结合o

Java Jackson核心注解使用详解

《JavaJackson核心注解使用详解》:本文主要介绍JavaJackson核心注解的使用,​​Jackson核心注解​​用于控制Java对象与JSON之间的序列化、反序列化行为,简化字段映射... 目录前言一、@jsonProperty-指定JSON字段名二、@JsonIgnore-忽略字段三、@Jso

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义