epoll详解

一、epoll内核调用

1、内核事件表

1.epoll_create函数

epoll是Linux特有的I/O复用函数,epoll使用一组函,而不是一个数。

epoll把文件描述符fd放到了内核的一个事件表里,所以无须每次调用重传fd

epoll需要一个额外的fd来唯一的标识内核中的事件表:epoll_create函数

size参数不起作用,仅告诉内核事件表的大小

epoll_create函数返回的文件描述符将作用其他epoll系统调用的第一个参数,用来指定要访问的内核事件表

2.epoll_ctl函数

用来操作epoll的内核事件表:

 fd是要操作的文件描述符,op是指定操作类型,操作类型有三种:

EPOLL_CTL_ADD:往事件表中注册fd上的事件

EPOLL_CTL_MOD:修改fd上的注册事件

EPOLL_CTL_DEL:删除fd上的注册事件

event参数指定事件,是epoll_event结构指针类型,其结构体定义如下:

 events成员描述事件类型,epoll的事件类型基本和poll是一致的,但是在其基础上有额外的两个事件类型:EPOLLET和EPOLLONESHOT。

data成员用于存储用户数据,epoll_data_t定义如下:

 epoll_data_t 是一个联合体,其四个成员使用最多的是fd,指定文件操作符。

ptr用以指定与fd相关的用户资源。

epoll_ctl 成功返回0,失败返回-1 并设置errno。

2、epoll_wait函数

1.epoll_wait函数

epoll系列系统调用的主要接口:epoll_wait函数

epoll_wait函数在一段超时时间等待一组文件描述符上的事件:

 成功时返回就绪的文件描述符膈俞,失败返回-1并设置errno。

timeout参数指定epoll的超时值

maxevents参数指定最多监听多少个事件,必须大于0

2.epoll_wait函数的检测过程

epoll_wait检测到事件

就将所有就绪的事件从内核事件表中复制到events指向的数组中,此数组仅用于检测就绪事件,poll、select的数组参数即用于传入用户注册的事件,又用于输出内核检测的就绪事件。

epoll_wait极大地提高 了应用程序索引就绪文件描述符的效率

3、LT和ET模式

epoll对文件描述符的操作有两种模式:LT(电平触发)模式 和 ET(边沿触发)模式

1.LT(Level Trigger)模式

LT模式是默认的工作模式,这种模式下的epoll相当于一个效率较高poll

2.ET(Edge Trigger)模式

ET模式是epoll的高效模式,当epoll内核事件表中注册一个文件描述符上的EPOLLET事件时,epoll将以ET模式来操作。

3.LT和ET的效率

使用LT模式时,当epoll_wait检测到fd上有事件并通知应用程序后,应用程序可以不立即处理该事件,这样下一次调用epoll_wait时,epoll_wait还会向告诉应用程序通知此事件,直到事件被处理;

使用ET模式时,epoll_wait检测到fd上有事件并通知应用程序后,应用程序必须立即处理此事件,ET模式很大程度降低了同一个epoll事件被重复触发的次数,

由此可见ET效率和LT高。

每个使用ET模式的fd都应该是非阻塞的。如果fd是阻塞的那么读/写操作会处于饥渴状态(因没有后续的事件而一直处于阻塞)。

4、EPOLLONESHOT事件

 即使使用ET模式,socket上某个事件还是可能会被触发多次,由此在并发程序会引起一个问题:

一个线程在读取完某个socket上的数据后开始处理这些数据,而在数据的处理过程中该socket上又有新数据可读,此时另外一个线程被唤醒来读取这些新的数据,于是就出现了两个线程读取一个socket的情况。

EPOLLONESHOT事件实现的就是 :一个socket连接在任一时刻都只被一个线程读取。

注册过EPOLLONESHOT事件的fd,操作系统最多触发其上注册的一个事件(可读、可写或异常),且只触发一次,除非使用epoll_ctl重置fd上注册的EPOLLONESHOT事件(每次注册完EPOLLONESHOT事件的socket被处理完毕,该线程应该立即重置EPOLLONESHOT事件,从而让其他工作线程有机会继续处理这个socket)。

 

posted @ 2022-04-28 10:45  NK-cat  阅读(1584)  评论(0编辑  收藏  举报