news 2026/7/23 2:48:51

muduo网络库(六):Poller类与IO复用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
muduo网络库(六):Poller类与IO复用

muduo网络库(六):Poller类与IO复用

  • muduo网络库(六):Poller类与IO复用
    • 概述
    • EpollPoller 子类
      • 核心方法
    • Channel 与 epoll_event 的绑定机制
    • newDefaultPoller 为什么单独放在一个文件中
    • 精髓总结

muduo网络库(六):Poller类与IO复用

概述

Poller是 muduo 网络库中IO 复用机制的抽象层,它封装了不同的多路复用技术(如 epoll、poll、select),为上层提供统一的接口。EpollPoller是其基于 Linux epoll 实现的具体子类。

Poller类中只有两个核心成员:

  • 一个channels_Map,存储当前所有的 Channel
    • 一个loop_指针,标识当前所属的 EventLoop
      其余都是纯虚函数,因为每种具体的多路复用技术(epoll、poll 等)都有各自的实现逻辑。

EpollPoller 子类

EpollPoller是对 epoll 的封装,因此有两个关键成员:

  • epollFd_:epoll 的监听文件描述符,作为"监听仓库"
    • events_vector<epoll_event>,保存 epoll_wait 返回的事件容器

核心方法

1. updateChannel()

先把新 Channel 加入到channels_Map 中(删除则修改 index),然后根据 Channel 的状态调用 epoll 的update函数(即epoll_ctl)。

状态转换逻辑如下:

  • kNew(未注册)→ 加入 channels Map → 变为kAdded
    • kAdded(已注册)→ 如果无感兴趣事件(isNoneEvent())→EPOLL_CTL_DEL→ 变为kDeleted
    • kAdded→ 如果有事件变更 →EPOLL_CTL_MOD
    • kDeleted(已删除)→ 重新添加 →EPOLL_CTL_ADD→ 变为kAdded
      通过 Channel 的index_成员来标识它在 epoll 中的状态,从而决定是添加、修改还是删除。

2. removeChannel()

channels_Map 中删除指定的 Channel,同时从 epoll 中删除。

3. poll()

调用epoll_wait()函数监听所有已注册的 fd。要监听的 fd 已经通过updateChannel加入到epollFd_中了。返回结果存储在events_中(必要时会动态扩容)。

4. fillActiveChannels()

遍历events_,由于epoll_event结构中的data.fddata.ptr指向的 Channel 都是绑定的,直接将data.ptr转换为Channel*加入到activeChannels中即可。后续在EventLoop::loop()中遍历activeChannels,调用Channel::handleEvent()处理事件。

注意:Poller 只是监听 fd,当监听到可读事件后,上层调用accept()才真正建立连接。Poller 相当于只负责监听当前线程的 fd,构建 channels,是 EventLoop 的一部分。

Channel 与 epoll_event 的绑定机制

Poller结合EpollPoller将 epoll 机制封装,每个 EventLoop 只有一个 Poller,用于监听所有 Channel。核心在于利用epoll_event.data.ptr将 Channel 和 epoll 监听的事件绑定起来。

注册时绑定:

structepoll_eventevent;event.events=channel->events();event.data.ptr=channel;// 将 Channel 指针存入 epoll_event::epoll_ctl(epollFd_,operation,fd,&event);

事件触发时取回:

Channel*channel=static_cast<Channel*>(events_[i].data.ptr);

这样就将事件 Channel 与 IO 多路复用机制联系了起来,而它们都在 EventLoop 类中协作。

newDefaultPoller 为什么单独放在一个文件中

DefaultPoller::newDefaultPoller()是一个工厂方法,用于:

  1. 动态选择 IO 复用实现:根据环境变量MUDUO_USE_POLL决定使用哪种 IO 复用方式
    1. 解耦架构:EventLoop 不需要直接依赖具体的 epoll 或 poll 实现,通过工厂方法获取。本项目中只实现了 epoll,所以默认返回EpollPoller
      这体现了依赖倒置原则:抽象不依赖于具体,具体依赖于抽象。单独放在一个文件中的关键原因是避免循环依赖

如果把newDefaultPoller放在Poller.cc中实现,Poller.cc需要包含具体子类的头文件#include "EPollPoller.h",而EPollPoller.h又需要继承Poller,包含#include "Poller.h",这就形成了循环依赖,导致编译失败。

Poller.h (抽象基类) ↑ 继承 EPollPoller.h DefaultPoller.cc (工厂方法) → 包含 Poller.h 和 EPollPoller.h → 负责创建具体实例

将工厂方法单独放在DefaultPoller.cc中,打破了这种循环依赖,让架构更加清晰。

精髓总结

Poller 类的设计体现了几个关键思想:

  • 多态抽象Poller定义统一接口,EpollPoller提供具体实现,上层代码不感知底层细节
    • epoll_event.data.ptr 绑定:巧妙利用 epoll 的data.ptr字段,将事件和 Channel 直接关联,零开销取回
    • 工厂模式解耦newDefaultPoller单独编译,避免循环依赖,遵循依赖倒置原则
    • 每个 EventLoop 一个 Poller:符合 One Loop Per Thread 模型,线程内无需加锁
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/23 2:48:18

PCB贴片打样服务解析:快速打样如何缩短电子产品研发周期?

PCB贴片打样是电子产品研发阶段非常关键的一环。无论是消费电子、工业控制设备还是智能硬件产品&#xff0c;在进入批量生产之前&#xff0c;通常都需要通过PCB贴片打样进行功能验证和电路测试&#xff0c;从而确保产品设计的可靠性和稳定性。在电子制造行业中&#xff0c;PCB贴…

作者头像 李华
网站建设 2026/7/23 2:46:18

Codex 遇到 CI 构建失败怎么办?从日志定位到最小修复的完整流程

摘要本地代码运行正常&#xff0c;提交到仓库后却在 CI 阶段失败&#xff0c;是开发中非常常见的问题。原因可能来自 Node.js 版本、环境变量、依赖锁文件、测试顺序或构建配置。本文介绍如何让 Codex 分阶段分析 CI 日志、定位根因并完成最小范围修复&#xff0c;避免为了让流…

作者头像 李华
网站建设 2026/7/23 2:43:11

现代C++:内存模型和atomic:理解并发的复杂性

上一讲我们讨论了一些并发编程的基本概念&#xff0c;今天我们来讨论一个略有点绕的问题&#xff0c;C 里的内存模型和原子量。C98 的执行顺序问题C98 的年代里&#xff0c;开发者们已经了解了线程的概念&#xff0c;但 C 的标准里则完全没有提到线程。从实践上&#xff0c;估计…

作者头像 李华
网站建设 2026/7/23 2:42:31

C#委托、事件和lambda表达式

委托委托就像是方法的类型&#xff0c;有了委托就可以把方法当参数传来传去&#xff0c;或者在一个变量里随时换掉要执行的方法。// 1. 声明一个委托类型&#xff08;定义&#xff1a;我能代表哪种方法&#xff09; public delegate void MyDelegate(string msg);// 2. 写一个符…

作者头像 李华
网站建设 2026/7/23 2:42:09

真激动,千问新人优惠券大放送!激活码:千问新人福利yPBm3m

最近整理了通义千问新用户得福利的小技巧&#xff0c;把最新的信息分享给大家&#xff1a;操作步骤先在手机应用商店找到千问APP&#xff0c;用之前没用过它的手机号注册登录&#xff1b;跟着APP里的指引绑定支付宝账号&#xff0c;这一步是拿到福利和抵扣的必要环节&#xff1…

作者头像 李华
网站建设 2026/7/23 2:41:11

如果f(3x+2)是奇函数,求f(x)的对称中心

如果 f(3x2) 是奇函数&#xff0c;那么 f(x) 关于点 (2, 0) 对称。 推导过程&#xff1a; 奇函数定义&#xff1a;令 ( g(x) f(3x2) )&#xff0c;则 ( g(-x) -g(x) )。代入得&#xff1a; ( f(-3x2) -f(3x2) )。换元&#xff1a;令 ( t 3x2 )&#xff0c;则 ( -3x2 4 - t…

作者头像 李华