muduo网络库学习(四)事件驱动循环EventLoop

本文详细介绍了muduo网络库的EventLoop设计,包括其作为Reactor模型的单线程任务特性,线程池和EventLoopThread的组织结构,以及Poller、TimerQueue、Channel的角色。EventLoop通过线程安全的机制处理回调函数,利用eventfd进行线程间通信,确保线程安全和高效执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

muduo的设计采用高并发服务器框架中的one loop per thread模式,即一个线程一个事件循环。
这里的loop,其实就是muduo中的EventLoop,所以到目前为止,不管是PollerChannel还是TimerQueue都仅仅是单线程下的任务,因为这些都依赖于EventLoop。这每一个EventLoop,其实也就是一个Reactor模型。
而多线程体现在EventLoop的上层,即在EventLoop上层有一个线程池,线程池中每一个线程运行一个EventLoop,也就是Reactor + 线程池的设计模式


梳理一下

  • 每个muduo网络库有一个事件驱动循环线程池EventLoopThreadPool
  • 每个线程池中有多个事件驱动线程EventLoopThread
  • 每个线程运行一个EventLoop事件循环
  • 每个EventLoop事件循环包含一个io复用Poller,一个计时器队列TimerQueue
  • 每个Poller监听多个Channel,TimerQueue其实也是一个Channel
  • 每个Channel对应一个fd,在Channel被激活后调用回调函数
  • 每个回调函数是在EventLoop所在线程执行
  • 所有激活的Channel回调结束后EventLoop继续让Poller监听

所以调用回调函数的过程中是同步的,如果回调函数执行时间很长,那么这个EventLoop所在线程就会等待很久之后才会再次调用poll。

整个muduo网络库实际上是由Reactor + 线程池实现的,线程池中每一个线程都是一个Reactor模型。在处理大并发的服务器任务上有很大优势。

简化的关系图如下,EventLoop只涉及Poller,Channel(简单涉及TcpConnection)和TimerQueue。

  • 白色三角,继承
  • 黑色菱形,聚合

这里写图片描述


一个事件驱动循环EventLoop其实就是一个Reactor模型,是一个单线程任务。主要包含io复用函数Poller,定时器队列TimerQueue以及激活队列。其他的就是一些辅助变量

  typedef std::vector<Channel*> ChannelList;

  bool looping_; /* atomic */
  std::atomic<bool> quit_;
  bool eventHandling_; /* atomic */
  bool callingPendingFunctors_; /* atomic */
  int64_t iteration_;
  /* 创建时保存当前事件循环所在线程,用于之后运行时判断使用EventLoop的线程是否是EventLoop所属的线程 */
  const pid_t threadId_;
  /* poll返回的时间,用于计算从激活到调用回调函数的延迟 */
  Timestamp pollReturnTime_;
  /* io多路复用 */
  std::unique_ptr<Poller> poller_;
  /* 定时器队列 */
  std::unique_ptr<TimerQueue> timerQueue_;
  /* 唤醒当前线程的描述符 */
  int wakeupFd_;
  // unlike in TimerQueue, which is an internal class,
  // we don't expose Channel to client.
  /* 
   * 用于唤醒当前线程,因为当前线程主要阻塞在poll函数上
   * 所以唤醒的方法就是手动激活这个wakeupChannel_,即写入几个字节让Channel变为可读
   * 注: 这个Channel也注册到Poller中
   */
  std::unique_ptr<Channel> wakeupChannel_;

  boost::any context_;

  // scratch variables
  /* 
   * 激活队列,poll函数在返回前将所有激活的Channel添加到激活队列中
   * 在当前事件循环中的所有Channel在Poller中
   */
  ChannelList activeChannels_;
  /* 当前执行回调函数的Channel */
  Channel* currentActiveChannel_;

  /* 
   * queueInLoop添加函数时给pendingFunctors_上锁,防止多个线程同时添加
   * 
   * mutable,突破const限制,在被const声明的函数仍然可以更改这个变量
   */
  mutable MutexLock mutex_;
 
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值