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

C++仿muduo库高并发服务器项目:Channel模块

前言

本篇文章所讲的是本人的个人项目仿muduo库高并发服务器中的Channel模块实现部分。

Channel模块介绍:

  • 功能:Channel模块是对⼀个描述符需要进⾏的IO事件管理的模块,实现对描述符可读,可写,错误…事件的

    管理操作,以及Poller模块对描述符进⾏IO事件监控就绪后,根据不同的事件,回调不同的处理函数功

    能。

  • 意义:让描述符的监控事件在用户态更易维护,触发事件后的操作流程更清晰

  • 功能设计:

    1. 对监控事件的管理:
      1. 描述符是否可读
      2. 描述符是否可写
      3. 对描述符监控可读
      4. 对描述符监控可写
      5. 解除可读事件监控
      6. 解除可写事件监控
      7. 解除所有事件监控
    2. 对监控事件触发后的处理:
      1. 设置对于不同事件的回调处理函数,明确触发某个事件后该如何处理。

线程安全:

Channel为什么要保证线程安全? 不保证线程安全有什么后果?

简单来说,Channel 必须保证线程安全,但其目标并非让自身成为一个能被任意线程随意调用的“线程安全类”,而是通过严格的规则,确保所有针对它的操作都在其所属的 IO 线程中执行,从而避免并发问题。

不保证线程安全的后果:

  • 数据竞争:多个线程同时修改 _events(监控事件)或 _revents(就绪事件),导致状态错乱,进而引发 Poller 监控错误的事件或漏掉事件。
  • 生命周期管理混乱:线程 A 正在处理 Channel 的事件回调,线程 B 却将 Channel 及其关联的连接对象销毁,导致线程 A 访问了已释放的内存,程序崩溃。
  • 事件处理乱序:线程池中的工作线程处理完业务逻辑后,想通过 send()发送数据。如果直接在其他线程调用,可能破坏 TCP 连接的字节流顺序,或与 IO 线程的读写事件产生竞争。

注意:这个模块应结合EventLoop模块学习,Channel中的EventLoop指针主要是为了保证线程安全,这也是muduo库的精髓之一,它并非采用复杂的锁机制来保证线程安全,那样会严重损害性能,而是采用了一种更为精巧的架构设计。其精髓可以概括为:通过“线程绑定”和“任务派发”机制,将可能引发竞态条件的操作约束在特定的单一线程内执行。

其实就是每个EventLoop都绑定了一个线程,内部含有一个线程ID,在开始时,都会调用assertInLoopThread()来检查当前线程的ID是否与threadId_一致。如果不一致,程序会直接报错终止。这就强制保证了诸如channel->EnableRead()这样的调用,最终必须在Channel所属的IO线程中执行。

想进一步了解,可以看看我写的关于EventLoop模块的博客。

代码实现

class EventLoop;
class Channel
{
private:int _fd;EventLoop* _loop;uint32_t _events;  //当前需要监控的事件uint32_t _revents; //当前连接触发的事件using EventCallback = std::function<void()>;EventCallback _read_callback;   //可读事件被触发的回调函数EventCallback _write_callback;  //可写事件被触发的回调函数EventCallback _error_callback;  //错误事件被触发的回调函数EventCallback _close_callback;  //连接断开事件被触发的回调函数EventCallback _event_callback;  //任意事件被触发的回调函数public:Channel(EventLoop* loop,int fd):_fd(fd),_events(0),_revents(0),_loop(loop){}int Fd(){return _fd;}//获取想要监控的事件uint32_t Events(){return _events;}//设置实际就绪事件void SetEvents(uint32_t events){_revents = events;}void SetReadCallback(const EventCallback& cb){_read_callback = cb;}void SetWriteCallback(const EventCallback& cb){_write_callback = cb;}void SetErrorCallback(const EventCallback& cb){_error_callback = cb;}void SetCloseCallback(const EventCallback& cb){_close_callback = cb;}void SetEventCallback(const EventCallback& cb){_event_callback = cb;}//当前是否监控了可读bool ReadAble(){return (_events & EPOLLIN);}        //当前是否可写bool WriteAble(){return (_events & EPOLLOUT);}    //启动读事件监控   void EnableRead(){_events |= EPOLLIN;Update();}  //启动写事件监控void EnableWrite(){_events |= EPOLLOUT;Update();}  //关闭读事件监控void DisableRead(){_events &= ~EPOLLIN;Update();}     //关闭写事件监控void DisableWrite(){_events &= ~EPOLLOUT;Update();}//关闭所有事件void DisableAll(){_events = 0;Update();}//移除监控void Remove();void Update();//事件处理,一旦触发事件调用它,用它来判断自己触发了什么事件,该去哪处理       void HandleEvent(){// 1. 优先处理错误事件:连接已致命,无需也无权再操作数据if (_revents & EPOLLERR) {if (_error_callback) _error_callback();// 错误通常是致命的,处理后直接返回,不再触发其他回调if (_event_callback) _event_callback(); // 错误事件也触发通用回调return;}// 2. 处理挂起事件:连接已完全断开且缓冲区数据已经读完if ((_revents & EPOLLHUP) && !(_revents & EPOLLIN)) {if (_close_callback) _close_callback();if (_event_callback) _event_callback(); // 关闭事件也触发通用回调return;}// 3. 处理读事件(包括普通数据、对端半关闭后的剩余数据)if (_revents & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) {if (_read_callback) _read_callback();}// 4. 处理写事件if (_revents & EPOLLOUT) {if (_write_callback) _write_callback();}// 5. 最后处理通用事件:任何事件触发(只要执行到这里)都会调用// 注意:由于错误和挂起事件已在上方返回,通用事件在那里被提前触发。// 而对于读/写事件,它在这里被触发。if (_event_callback) _event_callback();}    
};void Channel::Remove()
{_loop->RemoveEvent(this);
}void Channel::Update()
{_loop->UpdateEvent(this);
}
http://www.dtcms.com/a/524116.html

相关文章:

  • 网站开发前端php 后端python张家界seo
  • [特殊字符]兰亭妙微审美积累|总结三个情感化设计细节✨
  • 【数列求和】
  • 第一章-第二节-Cursor IDE与MCP集成.md
  • 做网站的的人收入多少钱wordpress 4.8.4 漏洞
  • 网站开发的英文书有什么如何做网站好看
  • 前端如何判断用户是否离开了当前页面?
  • Flutter项目搭建最佳实践
  • # AI高精度提示词生成项目——3D-VR 课件—— 最终仓库级 AI 提示词:生成《EduVR Studio》—— 专业级 3D-VR 课件创作平台
  • 巡检机器人落地攻略:RK3576驱动12路低延迟视觉
  • 网站开发 文件上传慢wordpress 上线到centos
  • 嘉兴网站建设多少钱广州装修公司口碑最好的是哪家
  • Docker Swarm 的负载均衡和平滑切换原理
  • RabbitMQ 发送方确认机制详解
  • Keepalived 多节点负载均衡配置
  • Windows下载安装配置rabbitmq
  • 了解前端连接 RabbitMQ 的方式
  • 【ROS2】ROS2+Qt6在编译时报错:target_link_libraries
  • 从0到1理解智能体模式
  • 怎么做家具定制网站qq自动发货平台网站怎么做
  • 微网站开发合同网站建设项目付款方式
  • HarmonyOS ArkUI框架中AceContainer类的成员变量定义
  • 数据结构——希尔排序
  • 分组卷积(Grouped Convolution)原理与应用详解
  • 【信道利用率】为什么卫星链路用 SW 协议效率低?ARQ 信道利用率公式 + 计算题全解!
  • 三极管MOS管
  • PHP拆分重组pdf,php拆分pdf指定页数,并合并成新pdf
  • 详解C语言数组
  • 鹤山做网站公司建设网站宣传
  • 微信网站开发视频教程开发一个小软件多少钱