Muduo类详解之EventLoop

        最核⼼的部分就是 EventLoop 、 Channel 以及 Poller 三个类,其中 EventLoop 可以看作是对业务线程的封装,⽽ Channel 可以看作是对每个已经建⽴连接的封装(即 accept(3) 返回的⽂件描述符)

 EventLoop

class EventLoop {
public:typedef std::function<void()> Function;// 初始化poller, event_fd,给 event_fd 注册到 epoll 中并注册其事件处理回调EventLoop();~EventLoop();// 开始事件循环 调⽤该函数的线程必须是该 EventLoop 所在线程,也就是 Loop 函数不能跨线程调⽤void Loop();// 停⽌ Loopvoid StopLoop();// 如果当前线程就是创建此EventLoop的线程 就调⽤callback(关闭连接 EpollDel) 否则就放⼊等待执⾏
函数区void RunInLoop(Function&& func);// 把此函数放⼊等待执⾏函数区 如果当前是跨线程 或者正在调⽤等待的函数则唤醒void QueueInLoop(Function&& func);// 把fd和绑定的事件注册到epoll内核事件表void PollerAdd(std::shared_ptr<Channel> channel, int timeout = 0);// 在epoll内核事件表修改fd所绑定的事件void PollerMod(std::shared_ptr<Channel> channel, int timeout = 0);// 从epoll内核事件表中删除fd及其绑定的事件void PollerDel(std::shared_ptr<Channel> channel);// 只关闭连接(此时还可以把缓冲区数据写完再关闭)void ShutDown(std::shared_ptr<Channel> channel);
代码随想录知识星球
从 EventLoop 的类定义中可以看出,除了⼀些状态量以外,每个 EventLoop 持有⼀个 Poller 的智能指针(对
epoll / poll 的封装),⼀个⽤于 EventLoop 之间通信的 Channel ,⾃⼰的线程 id,互斥锁以及装有等待处理函
数的 vector 。很明显, EventLoop 并不直接管理各个连接的 Channel (⽂件描述符的封装),⽽是通过
Poller 来进⾏的。 EventLoop 中最核⼼的函数就是 EventLoop::Loop() 。bool is_in_loop_thread();
private:// 创建eventfd 类似管道的 进程间通信⽅式static int CreateEventfd();void HandleRead(); // eventfd的读回调函数(因为event_fd写了数据,所以触发
可读事件,从event_fd读数据)void HandleUpdate(); // eventfd的更新事件回调函数(更新监听事件)void WakeUp(); // 异步唤醒SubLoop的epoll_wait(向event_fd中写⼊数据)void PerformPendingFunctions(); // 执⾏正在等待的函数(SubLoop注册EpollAdd连接套接字以
及绑定事件的函数)
private: std::shared_ptr<Poller> poller_; // io多路复⽤ 分发器int event_fd_; // ⽤于异步唤醒 SubLoop 的 Loop 函数中的
Poll(epoll_wait因为还没有注册fd会⼀直阻塞)std::shared_ptr<Channel> wakeup_channel_; // ⽤于异步唤醒的 channelpid_t thread_id_; // 线程idmutable locker::MutexLock mutex_;std::vector<Function> pending_functions_; // 正在等待处理的函数bool is_stop_; // 是否停⽌事件循环bool is_looping_; // 是否正在事件循环bool is_event_handling_; // 是否正在处理事件bool is_calling_pending_functions_; // 是否正在调⽤等待处理的函数
};
        从 EventLoop 的类定义中可以看出,除了⼀些状态量以外,每个 EventLoop 持有⼀个 Poller 的智能指针(对epoll / poll 的封装),⼀个⽤于 EventLoop 之间通信的 Channel ,⾃⼰的线程 id ,互斥锁以及装有等待处理函数的 vector 。很明显, EventLoop 并不直接管理各个连接的 Channel (⽂件描述符的封装),⽽是通过 Poller 来进⾏的。 EventLoop 中最核⼼的函数就是 EventLoop::Loop()
void EventLoop::Loop() {// 开始事件循环 调⽤该函数的线程必须是该EventLoop所在线程assert(!is_looping_);assert(is_in_loop_thread());is_looping_ = true;is_stop_ = false;while (!is_stop_) {// 1、epoll_wait阻塞 等待就绪事件auto ready_channels = poller_->Poll();is_event_handling_ = true;// 2、处理每个就绪事件(不同channel绑定了不同的callback)for (auto& channel : ready_channels) {channel->HandleEvents();}is_event_handling_ = false;// 3、执⾏正在等待的函数(fd注册到epoll内核事件表)PerformPendingFunctions();// 4、处理超时事件 到期了就从定时器⼩根堆中删除(定时器析构会EpollDel掉fd)poller_->HandleExpire();}is_looping_ = false;
}
        每个 EventLoop 对象都唯⼀绑定了⼀个线程,这个线程其实就在⼀直执⾏这个函数⾥⾯的 while 循环,这个 while 循环的⼤致逻辑⽐较简单。就是调⽤ Poller::poll() 函数获取事件监听器上的监听结果。接下来在 Loop ⾥⾯就会调⽤监听结果中每⼀个 Channel 的处理函数 HandlerEvent() 。每⼀个 Channel 的处理函数会 根据 Channel 中封装的实际发⽣的事件,执⾏ Channel 中封装的各事件处理函数。(⽐如⼀个 Channel 发⽣ 了可读事件,可写事件,则这个 Channel HandlerEvent() 就会调⽤提前注册在这个 Channel 的可读事件 和可写事件处理函数,⼜⽐如另⼀个 Channel 只发⽣了可读事件,那么 HandlerEvent() 就只会调⽤提前注册在这个 Channel 中的可读事件处理函数。
从中可以看到,每个 EventLoop 实际上就做了四件事
1. epoll_wait阻塞 等待就绪事件(没有注册其他fd时,可以通过event_fd来异步唤醒)
2. 处理每个就绪事件
3. 执⾏正在等待的函数(fd注册到epoll内核事件表)
4. 处理超时事件,到期了就从定时器⼩根堆中删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/769623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决SLF4J: Class path contains multiple SLF4J bindings.

JDK版本&#xff1a;jdk17 IDEA版本&#xff1a;IntelliJ IDEA 2022.1.3 SpringBoot 版本&#xff1a;v2.5.7 maven版本&#xff1a;3.6.3 文章目录 问题描述&#xff1a;原因分析&#xff1a;解决方案&#xff1a;参考资料&#xff1a; 问题描述&#xff1a; 当SpringBoot项目…

并发VS并行

参考文章 面试必考的&#xff1a;并发和并行有什么区别&#xff1f; 并发&#xff1a;一个人同时做多件事&#xff08;射击游戏队友抢装备&#xff09; 并行&#xff1a;多人同时处理同一件事&#xff08;射击游戏敌人同时射击对方&#xff09;

系统学习Python——装饰器:“私有“和“公有“属性案例-[Python不是关于控制]

分类目录&#xff1a;《系统学习Python》总目录 既然我已经用如此大的篇幅实现了Python代码的Private和Public属性声明&#xff0c;必须再次提醒&#xff0c;像这样为类添加访问控制不完全是Python的风格。实际上&#xff0c;除了充当装饰器使用的一个展示&#xff0c;大多数程…

解决ros2缺少cv_bridge包的问题——cv_bridge源码编译安装过程

安装流程 注意&#xff1a;cv_bridge 依赖boost 和 opencv 首先&#xff0c;和编译ros2功能包一样&#xff0c;先创建一个工作空间 mkdir -p cv_bridge_ws/src cd cv_bridge_ws/src然后&#xff0c;在src目录下&#xff0c;下载vision_opencv的源码,注意将-b galactic替换成…

制作 configure 文件极简教程

The magic behind configure, make, make install - How it works in Unix (thoughtbot.com) 如果要发布自己的源码&#xff0c;而自己的源码想通过configure&#xff0c;make&#xff0c;make install 编译安装&#xff0c;那么要为自己的源码建立 configure 文件&#xff0…

uniapp 安卓跳转到应用设置等页面

// #ifdef APP-PLUS const platform uni.getSystemInfoSync().platform if (platform android) {var main plus.android.runtimeMainActivity(); //获取activityvar pkName main.getPackageName();var Intent plus.android.importClass(android.content.Intent); var Set…

学习数据结构:算法的时间复杂度和空间复杂度

一、算法的复杂度 衡量一个算法的好坏&#xff0c;一般是从时间和空间两个维度来衡量的&#xff0c;即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢&#xff0c;而空间复杂度主要衡量一个算法运行所需要的额外空间。 算法的时间复杂度 算法中的基本操作的…

SAP BAS中Fiori开发的高阶功能(storyboard, navigation, guided development, variant)

1. 前言 在之前的几篇文章中&#xff0c;我介绍了SAP BAS的一些基本功能&#xff0c;包括账户申请&#xff0c;创建工作区&#xff0c;git的使用以及如何step-by-step去创建出你的第一个Fiori项目等等。在本篇中&#xff0c;我将进一步介绍一些在开发Fiori应用程序时会用到的高…

JAVA学习笔记19(面向对象编程)

1.面向对象编程 1.1 类与对象 1.类与对象的概念 ​ *对象[属性]/[行为] ​ *语法 class cat {String name;int age; }main() {//cat1就是一个对象//创建一只猫Cat cat1 new Cat();//给猫的属性赋值cat1.name "123";cat1.age 10; }​ *类是抽象的&#xff0c;…

前端使用正则表达式进行校验

一、定义 设计思想是用一种描述性的语言定义一个规则&#xff0c;凡是符合规则的字符串&#xff0c;我们就认为它“匹配”了&#xff0c;否则&#xff0c;该字符串就是不合法的。 在 JavaScript中&#xff0c;正则表达式也是对象&#xff0c;构建正则表达式有两种方式&#x…

【可用Claude Opus模型】Claude3国内镜像站,亲测完全超越GPT-4(可用Claude Opus,官网价值20刀)

#今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用Claude 3吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像站到处都是…

如何实现一个自己的脚手架工具

如何实现一个自己的脚手架工具 创建自定义全局命令获取命令行的交互参数终端交互下载远程项目代码 创建自定义全局命令 在项目文件夹中创建一个bin文件夹&#xff0c;再去npm init 初始化项目&#xff0c;生成的package.json 里面就有一个bin的选项参数指定了命令和执行文件路…

有效的括号字符串

只想用一个栈解决&#xff0c;可惜一直解决不了&#xff0c;因为 * 的问题无法解决 看到标答用了两个栈&#xff0c;一个栈存储 ( 另一个栈储存 * 思路&#xff1a;当s[k] 为 ( 或 * 进栈 &#xff0c; 当s[k] 为 ) 时 &#xff0c; 优先左括号出栈&#xff08;因为*有…

探索LLaMA模型:架构创新与Transformer模型的进化之路

引言 在人工智能和自然语言处理领域&#xff0c;预训练语言模型的发展一直在引领着前沿科技的进步。Meta AI&#xff08;前身为Facebook&#xff09;在2023年2月推出的LLaMA&#xff08;Large Language Model Meta AI&#xff09;模型引起了广泛关注。LLaMA模型以其独特的架构…

视频批量爬虫下载工具|可导出视频分享链接|抖音视频提取软件

便捷的视频批量爬虫软件操作指南 抖音视频下载界面图解 主要功能&#xff1a; 关键词批量提取视频和单独视频提取&#xff0c;提取后下载功能。 功能解析&#xff1a; 1. 关键词批量采集视频的解析 对特定关键词进行搜索和视频提取&#xff0c;例如输入“汽车配件”&#x…

2024年洗地机综合实力排行榜:谁才是真正的洗地神器?

近年来&#xff0c;洗地机在行业里&#xff0c;它集合了扫地和拖地以及自动清洁和除菌的功能&#xff0c;备受人们的喜爱&#xff0c;尤其是平时忙于工作并没有多少时间清洁家务的用户&#xff0c;但是对于第一次接触洗地机的用户来说&#xff0c;怎么选购洗地机也是个问题&…

【P1303】 A*B Problem

A*B Problem 题目背景 高精度乘法模板题。 题目描述 给出两个非负整数&#xff0c;求它们的乘积。 输入格式 输入共两行&#xff0c;每行一个非负整数。 输出格式 输出一个非负整数表示乘积。 样例 #1 样例输入 #1 1 2样例输出 #1 2提示 每个非负整数不超过 1 0…

初识React(一)从井字棋游戏开始

写在前面&#xff1a; 磨磨唧唧了好久终于下定决心开始学react&#xff0c;刚刚接触感觉有点无从下脚...新的语法新的格式跟vue就像两种物种...倒是很好奇路由和store是怎么实现的了~v~&#xff0c;一点一点来吧&#xff01;&#xff01;&#xff01; (一)创建项目 使用vite…

【58. 最后一个单词的长度】

58. 最后一个单词的长度 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 class Solution { public: int lengthOfLastWord(string s) …

蓝桥杯算法 - DP

上一篇&#xff1a;[[蓝桥杯算法-排序、递归、全排列]] 动态规划&#xff08;dp&#xff09; dp即动态规划&#xff0c;常用于&#xff1a;数学&#xff0c;计算机科学&#xff0c;管理学&#xff0c;经济和生物信息学。 dp在生活中也很常见&#xff0c;如&#xff1a;你今天…