这是我参与「第四届青训营 」笔记创作活动的的第7天
Muduo事件处理之Poller类的设计
简要介绍下关联的几个类
1.1 Channel类
Channel类其中对应了一个文件描述符号表示监听了哪一个对象,并且是包括 感兴趣的事件:events , epoll返回的目前发生的事件:revents,并且设置了关注的事件的回调函数
Channel一般是用作别的类的直接成员或者是间接的成员
1.2 EventLoop类
很著名的思想:
one loop per thread, 每个线程对应的一个EventLoop.在对事件处理的这个过程中承担着算是中间人的作用,
EventLoop内涵了成员变量:Poller & Channel并且
POLLER & CHANNEL中都有所属的EVENTLOOP对象
1.3 事件总体的改变的趋势(事件的注册)
Channel update remove => EvnentLoop updateChannel removeChannel => Poller updateChannel removeChannel
- 某个地方调用Channel的
update等Channel所属的EventLoop对channel进行操作EventLoop调用底层的IO复用类:epoll其中Channel中的很多的状态信息:index、fd等用于辅助epoll对其的操作
2.1 epoll的使用
1、内核事件表
不同于
select & poll, epoll的创建需要一个fd, 之后使用的是epoll内置的对应的函数进行操作
epoll_create(int size)size只是一个提示说需要多大的空间, 返回的就是文件描述符
2、epoll的操作函数
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
- 第一个参数就是上面创建的epoll fd
- 第二个参数就是选择 添加、修改、删除(内置的宏定义)
- 关注哪一个文件描述符
- 对应的事件
3、epoll中event结构内容
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
4、epoll_wait
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)如果检测到数据了,就将对应的事件复制到第二个参数:事件表中,然后遍历执行对事件的处理就可以了
2.2 EPOLLER的设计细节
poll() : 封装epoll_wait
//epoll_wait, 将发生的事件填入activeChannels
TimeStamp Epoller::poll(int timeoutMs, ChannelList* activeChannels)
{
int numEvents = ::epoll_wait(epollfd_,
&(*events_.begin()),
static_cast<int>(events_.size()),
timeoutMs);
TimeStamp now(TimeStamp::now());
if (numEvents > 0) {
//TODO: log
printf("%d events happend\n", numEvents);
//将发生的事件填充进activeChannel中去
fillActiveChannels(numEvents, activeChannels);
//将事件表进行扩容
if (events_.size() == numEvents) {
events_.resize(events_.size() * 2);
}
} else if (numEvents == 0) {
//do nothing
} else {
if (errno != EINTR) {
printf("EPoller::poll() : epoll_wait error\n");
}
}
return now;
}
直接向上面讲的一样,调用
epoll_wait, 遍历活跃的事件,填充到activeChannel中去
epoll_ctl
总的流程:fd所在的Channel想要注册事件,通过Channel对应的owner Loop(也就是属于哪一个事件循环)去调用
update, Channel通过成员变量Epoller进行实际上的调用
下面是实际上的对于
epoll_ctl的使用, 创建event结构然后调用,注册事件
\