当前位置: 首页 > news >正文

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 模型,线程内无需加锁
http://www.cnnetsun.cn/news/3593824.html

相关文章:

  • PCB贴片打样服务解析:快速打样如何缩短电子产品研发周期?
  • Codex 遇到 CI 构建失败怎么办?从日志定位到最小修复的完整流程
  • 现代C++:内存模型和atomic:理解并发的复杂性
  • C#委托、事件和lambda表达式
  • 真激动,千问新人优惠券大放送!激活码:千问新人福利yPBm3m
  • 如果f(3x+2)是奇函数,求f(x)的对称中心
  • ESP32网络电台DIY:低成本构建物联网音频系统
  • 2026年AI大模型岗位趋势与核心技术解析
  • Loop Engineering 学习笔记:从手写 Prompt 到设计循环
  • 多语言句子嵌入与可靠性审计:技术原理与部署实践
  • 深入解析TI MibSPI并行模式与多缓冲机制:高速嵌入式通信实战
  • 从双雄到三强:Kimi K3暂停注册、DeepSeek V4满血回归,中国AI正在改写全球游戏规则
  • Qwen 3.8大模型本地部署与交互应用开发实战指南
  • 【深度】别再神话 Skill 了——一个完整 Skill 到底由什么组成,为什么多数 Skill 跑不起来
  • RAG Chunk 策略怎么定?固定长度 vs 语义分块 vs Agent 分块
  • P1025 数的划分 题解复盘
  • AI生成文本检测技术解析:从特征识别到学术诚信实践
  • Claude Code离线安装方案揭秘:从零搭建企业级AI编程助手环境
  • Linux服务器WebDriver启动Chrome浏览器失败排查指南
  • 51单片机烧烤机设计(附代码与仿真)
  • MHmarkets:聚焦细节,看看风控思路的关键框架
  • ChatGPT宕机启示:构建抗脆弱工作流与容灾策略
  • 中国制造开源AI权重模型:从技术突破到工程实践
  • 纠缠几何:统一量子电路切割、经典难度与可训练性的新框架
  • AI换脸工具,2026年换脸工作流,5款实测解析
  • RTX 3080部署70亿参数大语言模型:本地量化推理实战指南
  • 企业API限流困境与多Key架构解决方案
  • 国产AI大模型本地化部署指南:月之暗面联合阿里模型实战测试
  • 欧易OKX年夜饭活动:高端服务与科技细节解析
  • Unity后处理堆栈Volume系统:从原理到实战,掌握效果混合与动态控制