重写muduo之EPollPoller

1、EPollPoller.h

EPollPoller的主要实现:作为poller的派生类,把基类给派生类保留的这些纯虚函数的接口实现出来。

override表示在派生类里面,这些方法是覆盖方法。必须由编译器来保证在基类里面一定有这些函数的接口的声明。在派生类要重写他们。
给EPollPoller的析构函数写override,就是让编译器给你检查基类的析构一定是虚函数。
底层是vector,放EventList,可以动态地扩容。
成员变量的epollfd要通过epoll_create来创建,映射的就是epoll底层的文件系统

#pragma once
#include "Timestamp.h"
#include "Poller.h"#include <vector>
#include <sys/epoll.h>/*** epoll的使用* epoll_create* epoll_ctl  add/mod/del* epoll_wait
*/
class EPollPoller:public Poller
{
public:EPollPoller(EventLoop* loop);//epoll_create~EPollPoller()override;//重写基类Poller的抽象方法Timestamp poll(int timeoutMs,ChannelList* activeChannels)override;//epoll_waitvoid updateChannel(Channel* channel)override;//epoll_ctlvoid removeChannel(Channel* channel)override;//epoll_ctl
private:static const int kInitEventListSize=16;//给vector<epoll_event>初始化的长度using EventList=std::vector<epoll_event>;//填写活跃的连接void fillActiveChannels(int numEvents,ChannelList* activeChannels)const;//更新channel通道void update(int operation,Channel* channel);int epollfd_;EventList events_;
};

2、EPollPoller.cc

epoll_wait:第2个参数epoll_event 是最终发生事件的fd,返回值是发生事件fd的数量。

epoll_create的参数size在Liunx内核2.6.8以后没有意义了,但是必须是大于0的数


epoll_create1,flags=0时和epoll_create一样,提供了行为选项EPOLL_CLOEXEC

当我们去使用epoll_create1的时候,创建的epollfd,然后在当前线程里面再去fork创建一个子进程,然后用exec替换子进程的时候,在子进程里面就把父进程设置成标志的fd,资源就都给关闭了。

结构体的fd就是epoll要监听的事件,ptr指向fd对应的channel,channel包含fd以及感兴趣的事件

#include "EPollPoller.h"
#include "Logger.h"
#include "Channel.h"#include <errno.h>
#include <unistd.h>
#include <string.h>// channel还没有被添加到Poller中
const int kNew = -1; // channel的成员index_=-1
// channel已经添加到Poller中
const int kAdded = 1;
// channel从Poller中删除
const int kDeleted = 2;EPollPoller::EPollPoller(EventLoop *loop): Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSize) // vector<epoll_event> 默认大小16
{if (epollfd_ < 0){LOG_FATAL("epoll_create error:%d \n", errno);}
}EPollPoller::~EPollPoller()
{::close(epollfd_);
}//epoll_wait 
//eventloop会创建一个channellist,并把创建好的channellist的地址传给poll
//poll通过epoll_wait监听到哪些fd发生了事件,把真真正正发生事件的channel通过形参发送到eventloop提供的实参里面 
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{// 实际上应该用LOG_DEBUG输出日志更为合理,可以设置开启或者不开启 因为LOG_INFO是每次都要输出的,会影响epoll的效率LOG_INFO("func=%s => fd total count:%lu\n", __FUNCTION__, channels_.size());//events_.begin()返回首元素的迭代器(数组),也就是首元素的地址,是面向对象的,要解引用,就是首元素的值,然后取地址 //就是vector底层数组的起始地址   static_cast类型安全的转换   timeoutMs超时时间 int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs); //全局的变量errno,库里的,poll可能在多个线程eventloop被调用 ,所以用局部变量存起来 int saveErrno = errno;  // 在loop开始时,保存当前loop的errno,防止中间操作发生错误对全局的errno进行改写,那在日志打印的时候就获取不到当前loop的errno了Timestamp now(Timestamp::now());if (numEvents > 0)//表示有已经发生相应事件的个数 {LOG_INFO("%d events happened \n", numEvents);fillActiveChannels(numEvents, activeChannels);// 如果返回的numEvents和实际vector中的events的长度是一样的,说明这一轮监听的所有的event都发生事件了,就要进行扩容了if (numEvents == events_.size()){events_.resize(events_.size() * 2);}}else if (numEvents == 0) // 没有事件发生,超时{LOG_DEBUG("%s timeout!\n", __FUNCTION__);}else // 发生错误{if (saveErrno != EINTR) // EINTR=>外部中断,不等于外部的中断 ,是由其他错误类型引起的 {errno = saveErrno; //适配 ,把errno重置成当前loop之前发生的错误的值 LOG_ERROR("EPollPoller::poll() err!");}}return now;
}// channel update remove=>EventLoop updateChannel removeChannel=>Poller updateChannel removeChannel
/***                   EventLoop   =>    poller.poll*          ChannelList        Poller*                             ChannelMap   <fd,Channel*>  (保存的是向poller注册过的channel)  epollfd*/
void EPollPoller::updateChannel(Channel *channel)
{const int index = channel->index();LOG_INFO("func=%s=> fd=%d events=%d index=%d \n", __FUNCTION__, channel->fd(), channel->events(), index);if (index == kNew || index == kDeleted)//未添加或者已删除 {if (index == kNew)//未添加,键值对写入map中 {int fd = channel->fd();channels_[fd] = channel;}channel->set_index(kAdded);update(EPOLL_CTL_ADD, channel);//相当于调用epoll_ctl,添加1个channel到epoll中 }else // channel已经在poller上注册过了{int fd = channel->fd();if (channel->isNoneEvent()) // channel对任何事件都不感兴趣,不需要poller帮忙监听了 {update(EPOLL_CTL_DEL, channel);//删除已注册的channel的感兴趣的事件 channel->set_index(kDeleted);}else{update(EPOLL_CTL_MOD, channel);}}
}
// 从poller中删除channel
void EPollPoller::removeChannel(Channel *channel)
{int fd = channel->fd();channels_.erase(fd);LOG_INFO("func=%s => fd=%d\n", __FUNCTION__, fd);int index = channel->index();if (index == kAdded)//如果已注册过 {update(EPOLL_CTL_DEL, channel);//通过epoll_ctl 删掉 }channel->set_index(kNew);//设置成未添加的状态 
}// 填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{for(int i=0;i<numEvents;i++){Channel* channel=static_cast<Channel*>(events_[i].data.ptr);channel->set_revents(events_[i].events);activeChannels->push_back(channel);//EventLoop就拿到了它的poller给它返回的所有发生事件的channel列表了//至于EventLoop拿到这些channel干什么事情,我们看 EventLoop的代码 }
}// 更新channel通道  epoll_ctl add/mod/del
void EPollPoller::update(int operation, Channel *channel)
{epoll_event event;memset(&event, 0, sizeof event);int fd = channel->fd();event.events = channel->events();//返回的就是fd所感兴趣的事件 event.data.fd = fd;event.data.ptr = channel;//绑定的参数 if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)//把fd相关事件更改 {if (operation == EPOLL_CTL_DEL){LOG_ERROR("epoll_ctl del error:%d\n", errno);}else{LOG_FATAL("epoll_ctl add/mod error:%d\n", errno); // add/mod如果失败了,是无法挽回的,所以LOG_FATAL会自动exit}}
}

channel要把自己注册到poller上,但channel无法与poller直接通信,channel调用的是EventLoop的updatechannel和removechannel,EventLoop的updatechannel和removechannel最终还是调用的EPollPoller,做的相当于是epoll_ctl,最后进行epoll_wait就是EPollPoller中的poll函数,使用vector数组存放发生的事件,如果返回值numEvents和vector数组长度一样,说明可能还有更多的事件没有处理,需要扩容,下一轮再来处理,因为muduo库采用的是LT模式,没有处理的事件会不断上报。

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

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

相关文章

从OutputStream类看Java中的IO流操作

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

C#连接S7-200 smart通讯测试

honeytree 一、编程环境 VS2022软件&#xff0c;选择windows窗体应用&#xff08;.NET FrameWork&#xff09;&#xff1a;​博途TIA/WINCC社区VX群 ​博途TIA/WINCC社区VX群 添加NuGet程序包&#xff1b;S7netplus 二、引用http://S7.net 三、建立PLC链接 S7-200smart和…

使用Docker安装Jenkins

大家好&#xff0c;今天给大家分享如何使用docker安装jenkins&#xff0c;关于docker的安装和常用命令可以参考下面两篇文章&#xff0c;使用docker可以提高资源利用率&#xff0c;能够在不同的环境中轻松迁移和部署应用&#xff0c;在本文中就不过多赘述了。 Docker常用命令 …

工厂模式+策略模式完成多种登录模式的实现

前提 &#xff08;简单工厂不属于设计模式&#xff0c;而是一种编程思想【抽象一层出来】&#xff09;工厂方法模式、抽象工厂模式 以上都是为了解耦&#xff0c;如果考虑多个纬度&#xff08;如需要同时考虑多种电器&#xff0c;多种品牌&#xff09;则优先考虑抽象工厂。 …

怎么通过Java语言实现远程控制无人售货柜

怎么通过Java语言实现远程控制无人售货柜呢&#xff1f; 本文描述了使用Java语言调用HTTP接口&#xff0c;实现控制无人售货柜&#xff0c;独立控制售货柜、格子柜的柜门。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂商1智能WiFi控…

ASP.NET网上图书预约系统的设计

摘 要 《网上图书预约系统的设计》是以为读者提供便利为前提而开发的一个信息管理系统&#xff0c;它不仅要求建立数据的一致性和完整性&#xff0c;而且还需要应用程序功能的完备、易用等特点。系统主要采用VB.NET作为前端的应用开发工具&#xff0c;利用SQL Server2000数据…

7-35 有理数均值

题目链接&#xff1a;7-35 有理数均值 一. 题目 1. 题目 2. 输入输出样例 3. 限制 二、代码 1. 代码实现 #include <iostream> using namespace std;// 计算公约数 int calGcd(int a, int b) {int gcd;bool negative false;if (a a / b * b) { // b整除areturn b;}…

Llama3-Tutorial之Llama3本地Web Demo部署

Llama3-Tutorial之Llama3本地 Web Demo部署 Llama3-Tutorial之Llama3本地Web Demo部署章节。 参考&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 1. 环境配置 conda create -n llama3 python3.10conda activate llama3conda install pytorch2.1.2 torchvision0…

【RAG 论文】SKR:Self-Knowledge 指导下的 RAG

论文&#xff1a;Self-Knowledge Guided Retrieval Augmentation for Large Language Models ⭐⭐⭐⭐ Tsinghua, arXiv:2310.05002 文章目录 一、论文速读二、实现细节2.1 数据的收集2.2 引出 LLM 的 Self-Knowledge 的方法1&#xff09;Direct Prompting2&#xff09;In-Cont…

stm32f103zet6_DAC_1_介绍

STM32微控制器系列的DAC&#xff08;数字到模拟转换器&#xff09;功能是其片上外设之一&#xff0c;用于将数字信号转换为模拟信号。DAC在许多应用中都非常有用&#xff0c;例如音频输出、模拟信号生成、闭环控制系统中作为模拟输出等。 STM32微控制器的DAC功能特点包括&…

概率论 科普

符号优先级 概率公式中一共有三种符号&#xff1a;分号 ; 、逗号 , 、竖线 | 。 ; 分号代表前后是两类东西&#xff0c;以概率P(x;θ)为例&#xff0c;分号前面是x样本&#xff0c;分号后边是模型参数。分号前的 表示的是这个式子用来预测分布的随机变量x&#xff0c;分号后的…

(论文阅读-优化器)Orca: A Modular Query Optimizer Architecture for Big Data

目录 摘要 一、简介 二、背景知识 2.1 大规模并行处理 2.2 SQL on Hadoop 三、Orca架构 四、查询优化 4.1 优化工作流 4.2 并行查询优化 五、Metadata Exchange 六、可行性 6.1 Minimal Repros 6.2 优化器准确性测试 七、实验 八、相关工作 8.1 查询优化基础 8…

自动驾驶融合定位:IMU内参模型及标定

自动驾驶融合定位&#xff1a;IMU内参模型及标定 一、 概述 标定的本质是参数辨识。首先明确哪些参数可辨识&#xff0c;其次弄清怎样辨识。 参数包括陀螺仪和加速度计各自的零偏、标度因数、安装误差。 辨识就比较丰富了&#xff0c;如果让各位先不局限于标定任务&#xf…

CasaOS玩客云安装memos开源云笔记并实现随时随地远程记笔记

文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 前言 本文主要介绍如何在CasaOS玩客云&#xff0c;使用Docker本地部署21.6K stars的热门开源云笔记服务memos&#xff0c;并结合cpolar内网穿透工具打…

libevent的使用

文章目录 libevent封装的框架思想常用函数分析使用fifo的读写未决和非未决bufferevent特性bufferevent函数客户端和服务器连接和监听libevent实现socket通信 libevent封装的框架思想 libevent框架&#xff1a;1. 创建 event_base (乐高底座)2. 创建 事件evnet 3. 将事件 添加…

MATLAB 变换

MATLAB 变换&#xff08;Transforms&#xff09; MATLAB提供了用于处理诸如Laplace和Fourier变换之类的变换的命令。转换在科学和工程中用作简化分析和从另一个角度查看数据的工具。 例如&#xff0c;傅立叶变换允许我们将表示为时间函数的信号转换为频率函数。拉普拉斯变换使…

软件测试面试问题汇总

一般软件测试的面试分为三轮&#xff1a;笔试&#xff0c;HR面试&#xff0c;技术面试。 前两轮&#xff0c;根据不同企业&#xff0c;或有或无&#xff0c;但最后一个技术面试是企业了解你“行不行”的关键环节&#xff0c;每个企业都会有的。 在平时的学习、工作中一定要善于…

使用tkinter开发的一款可扫描并删除本地文件敏感词的Windows软件

大致功能&#xff1a;可指定扫描Windows上的某个目录的所有文件&#xff0c;单个文件扫描&#xff0c;目前适配支持的文件后缀有&#xff1a;"pdf"、"txt、"doc"、"docx"&#xff0c;软件是开源的&#xff0c;大家可以在此基础上扩展更多类…

servlet-request(请求)-请求转发

request请求 request 请求index.jsplogin.jspsuccess.jspLoginServletSuccessServlet响应写入用户名和密码测试请求转发success.jsp页面测试请求转发SuccessServlet 页面测试重定向SuccessServlet 页面测试 request 请求 作用&#xff1a;获取浏览器发送过来的数据 组成部分&a…

【数据结构初阶】希尔排序

鼠鼠最近学习了希尔排序&#xff0c;做个笔记&#xff01; 希尔排序也是插入排序的一种捏&#xff01;本篇博客也是用排升序来举例捏&#xff01; 希尔排序是基于直接插入排序的&#xff0c;是由大佬D.L.Shell提出的。 目录 1.希尔排序 1.1.预排序 1.2.直接插入排序 2.希…