当前位置:网站首页>【MUDUO】EPOLLPOLLER事件分发器
【MUDUO】EPOLLPOLLER事件分发器
2022-07-23 06:27:00 【Cx330( ͡ _ ͡°)】
EPOLL的使用
/**
* epoll_create :
* 在EpollPoller构造函数里边肯定就是epoll_create, create完epoll,
* epoll记录在这个成员变量里边epollfd_,析构的时候是不是应该把这个成员变量给close掉哇?
* 所以这个epoll_create的设计创建涉及了构造和析构
* epoll_ctl :
* mod/del/add 相应的事件
* epoll_wait:
* 这步操作很明显就是在poll操作的
*/EPollPoller.h
#pragma once
#include "Poller.h"
#include "Timestamp.h"
#include <sys/epoll.h>
#include <vector>
class Channel;
class EPollPoller: public Poller
{
public:
EPollPoller(EventLoop *loop);
~EPollPoller() override;
//重写基类的Poller方法
Timestamp poll(int timeoutMs, ChannelList *activeChannel) override;
//这两个方法主要作用就是操作epoll_ctl
void updateChannel(Channel *channel) override;
void removeChannel(Channel *channel) override;
private:
//给下面的vector初始化大小
static const int kInitEventListSize = 16;
//填写活跃的连接
void fillActiveChannel(int numEvents, Channel *activeChannels) const;
//更新channel通道 :实际上在这个epollpoller里边,这个update相当于就是调用epoll_ctl,来对channel所包含的事件操作
void update(int operation, Channel *channel);
using EventList = std::vector<struct epoll_event> ;
int epollfd_;
EventList events_;
};epoll_create1 和epoll_create
/**
* @brief int epoll_create(int size):
* 内核版本大于2.6这个size就没有什么意义了,size必须要大于0就行
*
* @brief int epoll_create1(int flags):
* 它底下可以提供一个EPOLL_CLOEXEC的一个行为选项,clo就是close的意思,
* close_on_exec:就是表示说,当我去使用epoll_create的时候,创建的fd,
* 然后你在当前线程里再去fork创建一个子进程,然后用exec再去替换子进程的这个程序的时候,在子进程里边
* 就不会把这个父进程设置的这个标志的Fd资源就都给关闭了
* 默认的情况下:子进程是会继承父进程所有打开的fd资源
*
*/Channel和Epoll 的标识状态
1.kNew 从未添加到epoll
2.kAdded 已经添加到epoll中了
3.kDelete 这个channel已经从epoll中删除掉
再次强调EventLoop 和Channel 和Poller的关系
EventLoop 里边有两成员:ChannelList 和 Poller
Poller 里边有一个ChannelMap,ChannelMap里边:key就是FD,value就是Channel*
EventLoop里边应该放的是所有的。因为它是属于事件循环,所以放着所有的Channel,一个Channel就相当于表示一个FD。
那么poller里边这个ChannelMap表示的是:你向Poller里边注册过的话,就把这个channel地址记录在ChannelMap中。也就是说EventLoop中ChannelList的Channel是大于等于Poller里边的ChannelMap的Channel的
EPollPoller.cc
#include "EPollPoller.h"
#include "EventLoop.h"
#include "Logger.h"
#include "Channel.h"
#include <errno.h>
#include <unistd.h>
#include <string.h>
const int kNew = -1;
const int kAdded = 1;
const int kDelete = 2;
EPollPoller::EPollPoller(EventLoop *loop)
:Poller(loop)
,epollfd_(::epoll_create1(EPOLL_CLOEXEC))
,events_(kInitEventListSize) //vector<epoll_event>
{
if(epollfd_ < 0){
LOG_FATAL("epoll create error:%d \n", errno);
}
}
EPollPoller::~EPollPoller()
{
::close(epollfd_);
}
//重写基类的Poller方法
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannel)
{
//实际上应该用LOG_DEBUG输出日志更为合理
LOG_INFO("func = %s => fd total count:%lu \n",__FUNCTION__, channels_.size());
// &*events_.begin() 里边是struct epoll_event 元素
int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()),timeoutMs);
/**
* 会有多个线程访问这个poll(),因为一个线程就有一个EventLoop,一个EventLoop底层就有一个Poller
* 所以有可能有多个EventLoop的Poller在执行的时候都有可能访问,这个epoll_wait都有可能出错
* 都有可能去写这个errno,所以这个epoll_wait调用完了之后,先用一个局部变量存起来
*/
int saveError = errno;
//获取当前时间
Timestamp now(Timestamp::now());
if(numEvents > 0)
{
LOG_INFO("%d events happened \n", numEvents);
fillActiveChannel(numEvents, activeChannel);//让这个
if(numEvents == events_.size())
{
events_.resize(events_.size() * 2);
}
}else if(numEvents == 0) //只是超时了,没有什么错误
{
LOG_DEBUG("%s timeout!\n", __FUNCTION__);
}
else
{
if(saveError != EINTR)
{
//这一步操作就是拿到这个EventLoop开始的错误值,因为多线程会被覆盖掉errno的值
errno = saveError;
LOG_ERROR("EPollPoller::poll() err!");
}
}
return now;
}
//channel 调用update remove => EventLoop 调用updateChannel 然后调用removeChannel,最终调用了Poller
void EPollPoller::updateChannel(Channel *channel)
{
const int index = channel->index();
LOG_INFO("func = %s => fd = %d\tevents = %d\tindex = %d\n",__FUNCTION__, channel->fd(),channel->events(), index);
if(index == kNew || index == kDelete)
{
//如果从未添加过这个fd,就添加一次进poller里边的ChannelMap
if(index == kNew)
{
int fd = channel->fd();
channels_[fd] = channel;
}
//要么是新添加的,要么是你原来从poll删除了,现在又想往poll里边添加了
channel->set_index(kAdded);
update(EPOLL_CTL_ADD, channel);
}
else //channel已经在poller上注册过了
{
int fd = channel->fd();
//不对任何事件感兴趣
if(channel ->isNoneEvent())
{
update(EPOLL_CTL_DEL, channel);
channel->set_index(kDelete);
}
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);
}
channel->set_index(kNew);
}
//填写活跃的连接
void EPollPoller::fillActiveChannel(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列表了
}
}
void EPollPoller::update(int operation, Channel *channel)
{
epoll_event event;
bzero(&event, sizeof event);
int fd = channel->fd();
event.data.fd = fd;
event.events = channel->events();
event.data.ptr = channel;
if(::epoll_ctl(epollfd_, operation, fd, &event) < 0)
{
//如果事件是删除的的话,程序错误是可以容忍的,否则的话,fd的没有添加事件成功,就等于没有这个fd。所以不能容忍
if(operation == EPOLL_CTL_DEL)
{
LOG_ERROR("epoll_ctl del error:%d", errno);
}
else
{
LOG_FATAL("epoll_ctl add/mod error:%d", errno);
}
}
}边栏推荐
- Beifu PLC and C transmit structure type variables through ads communication
- When using fastjson to parse and assign JSON data, the order of JSON fields is inconsistent
- 成功 万象奥科与CODESYS技术联合调测
- Successful joint commissioning of Vientiane Aoke and CoDeSys Technology
- Space shooting part 2-2: enemy spirit
- Notes on the ninth day
- Beifu PLC and C transmit bool array variables through ads communication
- Jenkins持续集成报错stderr: fatal: unsafe repository (‘/home/water/water‘ is owned by someone else)
- [daily training] 814. Binary tree pruning
- Introduction to JVM memory model
猜你喜欢

【JZOF】10斐波那契数列

【NOI模拟赛】不知是哪一道CF的论文题(概率期望,鞅的停时定理)

Notes du jour 7

Uncaught (in promise) Neo4jError: WebSocket connection failure. Due to security constraints in your
![[jzof] 08 next node of binary tree](/img/4b/d8821e6e322b33e5abf26d48125e69.png)
[jzof] 08 next node of binary tree

The current situation of the industry is disappointing. After working, I returned to UC Berkeley to study for a doctoral degree

0722~线程池扩展

Numpy: quick start to basic operations

倍福和C#通过ADS通信传输Real类型

Google play app store may delete the overview of APP permissions and use a new combination of data security information
随机推荐
[actf2020 freshman competition]backupfile 1
【JZOF】07 重建二叉树
The unity model is displayed in front of the UI, and the UI behind it jitters
【JZOF】12矩阵中的路径
Image processing image feature extraction and description
Wu Enda machine learning series p31~p42
Shooting games lesson 1-2: using sprites
Jupyter notebook add existing virtual environment
Why does the GOM engine version automatically drop the line or flash back?
深入理解微信小程序的底层框架(一)
Day 10 notes
[jzof] 08 next node of binary tree
vs2019:constexpr 函数“qCountLeadingZeroBits”不能生成常量表达式
C language insert sort (direct insert sort)
JVM detailed parsing
Don't be silly to distinguish these kinds of storage volumes of kubernetes
【NOI模拟赛】不知是哪一道CF的论文题(概率期望,鞅的停时定理)
Beifu PLC and C transmit structure type variables through ads communication
Beifu and C transmit real type through ads communication
MetaApp开发面试题目