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

Muduo网络库重点技术详解

可能会出现线程安全的情况

EventLoop模块

我们还需要对连接本身做管理,未来我们对连接本身做管理的时候,虽然会调用绑定的 EventLoop 模块的函数,但是调用连接管理函数的时候不一定是在绑定的 EventLoop 模块绑定的线程中执行的,那么这些操作在执行的时候,需要进行一次判断,也就是判断当前调度的线程是不是对应的连接绑定的EventLoop所绑定的线程

可能有的同学不明白调用连接管理函数的时候不一定是在绑定的 EventLoop 模块绑定的线程中执行的

主线程向工作线程的连接发送数据:

  • 假设用户在主线程中调用某个连接的conn->send("hello")
  • 但该连接已被分配给工作线程2
  • muduo会检测到当前是主线程调用,而不是工作线程2
  • 于是将send操作封装成函数,通过runInLoop投递到工作线程2执行

关闭连接:

  • 主线程决定关闭某个连接conn->shutdown()
  • 该连接在工作线程3中
  • 关闭操作会被转发到工作线程3执行

EventLoop模块需要加锁

EventLoop模块 - eventfd

为什么需要这个 eventfd 呢? 我们说过,EventLoop 的执行流程是 监控文件描述符的事件,而这个监控我们肯定是需要阻塞的监控的,那么就会出现一种情况,我们的连接一直没有IO事件就绪,但是我们的任务队列中却已经放了很多任务了,这些对连接的管理操作就会一直得不到执行,那么未来就会出问题。 所以不仅是IO事件到来的时候需要结束这个阻塞状态,我们的任务队列中有新任务的时候也需要结束这个阻塞状态, 那么就需要一个事件的通知机制,也就是EventLoop所管理的Poller中也需要监控一个 eventfd 的读事件,每次我们向任务队列中放入任务的时候,我们需要向eventfd中写入一个数据,那么Poller 得Poll 操作就会返回,我们的 EventLoop 就能及时去执行这些任务队列的任务。

定时器模块 - 智能指针

。 当需要刷新定时任务的时候,我们只需要在 map 中找到对应的 TimerTask,然后直接在新的位置上在挂上这个任务。但是这时候存在一个问题,就是我们原来挂的这个定时任务并没有从数组中删除,同时我们也不敢直接删除,因为删除的话就需要析构了。所以我们至少不能在栈上为定时任务申请空间,而是需要在堆上申请,后续拿指针进行操作。

但是尽管如此,当我们的秒针走到这个超时任务的原定时间时,还是需要将这个位置上的任务全部执行。同时,如果是使用原生指针进行管理的话,那么我们还不能直接 clear ,我们需要一个一个遍历,然后 delete 释放堆空间。 

所以现在就面临两个问题: 原位置上的定时任务会执行,并且释放空间 ; 刷新之后,新位置的指针是个野指针。

那么基于这两个问题,我们可以使用 shared_ptr 来管理堆上开辟的定时任务。

原因很简单,我们需要秒针再经过原位置的时候,直接clear,释放了旧的 shared_ptr 对象,但是由于刷新过定时任务,我们还有一个该对象的 shared_ptr 对象在后面,那么就意味着,我们不会真正释放这个堆空间,只是将计数减 1 。 只有计数为 0 的时候,才会真正释放这个对象调用析构函数,而执行定时任务。 

那么就达到了刷新或者说延迟定时任务的目的。

但是又有一个问题,因为我们需要通过 map 中保存的定时任务对象的信息来构造一个新的 shared_ptr 对象加入到时间轮中,如果在 map 中也保存该对象的 shared_ptr 的话,就会占用一个计数,那么我们的定时任务就永远不会执行。 所以我们在设计 map 的时候,里面不能保存TimerTask对象指针的 shared_ptr ,而是保存他的 weak_ptr ,那么未来我们在延迟定时任务的时候,也可以直接通过 weak_ptr 来构造一个 shared_ptr , 但是我们的这个 weak_ptr 必须要从原始的shared_ptr 来,之后这样,后续使用 weak_ptr 构造的 share_ptr 对象才会和原始的 shared_ptr共享一个计数。

那么根据上面的思路,我们在数组中就使用 shared_ptr来管理任务对象,而在map中使用 shared_ptr的weak_ptr来保存定时任务的信息,方便查找以及构造新的shared_ptr 来增加原始shared_ptr的计数。

Connection模块 - shared_from_this

这个用法叫做自我引用。

为什么我们需要引进一个shared_from_this这样的接口呢? 

我们说了使用shared_ptr对所有的Connection对象进行管理,这样能够防止在操作的过程中资源被释放。 但是,我们在给 _message_cb 这样的回调函数传参的时候,如何保证传给他的shared_ptr对象是和管理Conenction 的shared_ptr的对象共享计数呢?

因为如果我们直接使用 shared_ptr<Connection> p (this) ,这样创建一个只能指针对象传参的时候,他的计数是独立的,并不会和TcpServer中管理Conenction的shared_ptr共享计数,那么我们就需要一个办法能够创建出一个和Conenction 的管理的shared_ptr对象共享技术的智能指针进行传参,而shared_from_this就可以解决这样的问题。

std::enable_shared_from_this<T> 内部维护了一个 std::weak_ptr<T>。当第一个 std::shared_ptr<T> 开始管理该对象时,这个 weak_ptr 被初始化。之后,当 shared_from_this() 被调用时,它将基于这个已经存在的 weak_ptr 返回一个新的 std::shared_ptr<T>,这个新的 shared_ptr 与原有的 shared_ptr 共享对对象的所有权。

那么使用这个接口,我们就能保证在这些回调函数在执行的时候,即使其他的地方调用了_svr_close_cb把TcpServer模块中的基础计数的智能指针释放了,这份资源也还存在,至少在我们这次函数栈帧内还存在,不会出现野指针的问题。

http://www.xdnf.cn/news/744211.html

相关文章:

  • tomcat服务器以及接受请求参数的方式
  • Java网络编程实战:TCP/UDP Socket通信详解与高并发服务器设计
  • uniapp uni-id Error: Invalid password secret
  • Linux531rsync定时同步 再回忆
  • 智能测试新范式:GenAI 与 Playwright MCP 如何重塑 QA 流程
  • 【Ubuntu】摸鱼技巧之虚拟机环境复制
  • C#WinForm程序时方法很多时Form.cs文件会很长,如何分别写入多个文件,partial class的作用体现出来了。
  • 矩阵快速幂算法快速上手
  • 极大似然估计例题——正态分布的极大似然估计
  • 尚硅谷redis7 99 springboot整合redis之连接集群
  • AppTrace 视角下 App 一键拉起:提升应用转化率的高效方案​
  • 使用Gemini, LangChain, Gradio打造一个书籍推荐系统 (第四部分)
  • 自动驾驶系列—Monocular 3D Lane Detection for Autonomous Driving
  • 【Web API系列】WebTransportSendStream接口深度解析:构建高性能实时数据传输的基石
  • Python实现P-PSO优化算法优化循环神经网络LSTM分类模型项目实战
  • 【技能拾遗】——家庭宽带单线复用布线与配置(移动2025版)
  • 【网络与信息安全】实验三 RSA加解密与签名验证
  • 澄清 STM32 NVIC 中断优先级
  • [网页五子棋][对战模块]实现游戏房间页面,服务器开发(创建落子请求/响应对象)
  • 中文NLP with fastai - Fastai Part4
  • 新视角!经济学顶刊QJE用文本分析探究新技术扩散
  • 简单cnn
  • go|channel源码分析
  • c# 如何中的 ? 与 ??
  • “粽”览全局:分布式系统架构与实践深度解析(端午特别版)
  • 《信号与系统》第 5 章 离散时间傅里叶变换
  • 2025年- H61-Lc169--74.搜索二维矩阵(二分查找)--Java版
  • Qt -下载Qt6与OpenCV
  • Python训练营打卡Day41
  • 5G-A:开启通信与行业变革的新时代