epoll系列系统调用
epoll是Linux特有的I/O复用函数。
epoll使用一组函数来完成任务。epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中。
epoll需要使用一个额外的文件描述符,来唯一标识内核中的事件表。
epoll事件表的文件描述符创建函数:
#include <sys/epoll.h>
int epoll_create( int size );
参数:
epoll系统调用的内核事件表操作函数:
#include <sys/epoll.h>
int epoll_ctl( int epfd, int op, int fd, struct epoll_event* event );
参数:
- 参数epfd:内核事件表的文件描述符;
- 参数fd:要操作的文件描述符;
- 参数op:指定操作类型;
- 参数event:指定事件,它是epoll_event结构指针类型;
epoll_ctl成功时返回0,失败则返回-1并设置errno。
操作类型
名称 | 作用 |
---|
EPOLL_CTL_ADD | 往事件表中注册fd上的事件 |
EPOLL_CTL_MOD | 修改fd上的注册事件 |
EPOLL_CTL_DEL | 删除fd上的注册事件 |
epoll_event的定义:
struct epoll_event
{
__uint32_t events;
epoll_data_t data;
};
结构体成员:
- events成员描述事件类型。epoll支持的事件类型和poll基本相同。表示epoll事件类型的宏是在poll对应的宏前加上"E",比如epoll的数据可读事件是EPOLLIN。但epoll由俩个额外的事件类型—EPOLLET和EPOLLONESHOT。
- data成员用于存储用户数据。
epoll的事件类型
事件 | 描述 | 是否可作为输入 | 是否可作为输出 |
---|
EPOLLIN | 数据(包括普通数据和优先数据)可读 | 是 | 是 |
EPOLLRDNORM | 普通数据可读 | 是 | 否 |
EPOLLRDBAND | 优先带数据可读(Linux不支持) | 是 | 是 |
EPOLLPRI | 高优先级数据可读,比如TCP带外数据 | 是 | 是 |
EPOLLOUT | 数据(包括普通数据和优先数据)可写 | 是 | 是 |
EPOLLWRNORM | 普通数据可写 | 是 | 是 |
EPOLLWRBAND | 优先级数据可写 | 是 | 是 |
EPOLLRDHUP | TCP链接被对方关闭,或者对方关闭写操作。它由GNU引入 | 是 | 是 |
EPOLLERR | 错误 | 否 | 是 |
EPOLLHUP | 挂起 | 否 | 是 |
EPOLLNVAL | 文件描述符没有打开 | 否 | 是 |
EPOLLET | 开启高效模式 | 否 | 否 |
EPOLLONSHOT | 操作系统最多触发其上注册的一个可读、可写或异常事件,且只触发一次 | 否 | 否 |
epoll_data_t的定义:
typedef union epoll_data
{
void* ptr;
int fd;
uin32_t u32;
uin64_t u64;
}epoll_data_t;
联合体成员:
-
成员 ptr:用于指定与fd相关的用户数据;
-
成员 fd :指定事件所从属的目标文件描述符;
由于epoll_data_t是一个联合体,所有不能同时使用其成员ptr和成员fd、因此,如果要将文件描述符和用户数据关联起来,以实现快速的数据访问,只能使用其他手段。比如放弃使用epoll_data_t的fd成员,而在ptr指向的用户数据中包含fd。
epoll系统调用的接口函数:
在一段超时时间内等待一组文件描述符上的事件。
#include <sys/epoll.h>
int epoll_wait( int epfd, struct epoll_event* events, int maxevents,int timeout );
参数:
- 参数epfd:内核事件表的文件描述符;
- 参数events:epoll_wait如果检测到事件,就将所有就绪的事件从内核事件表(由epfd参数指定)中复制到参数events指向的数组中,这个数组只用于输出epoll_wait检测到的就绪事件;
- 参数maxevents:指定最多监听多少个事件,它必须大于0;
- 参数timeout:指定epoll的超时值,单位是毫秒。当timeout为 -1时,epoll调用将永远阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回。
LT和ET模式
epoll对文件描述符的操作有俩种模式:LT(Level Trigger,条件触发)模式和ET(Edge Trigger,边缘触发)模式。
LT模式事默认的工作模式,这种模式下epoll相当于一个效率较高的poll。ET模式事epoll的高效工作模式。
LT工作模式:当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件。当应用程序下一次调用epoll_wait时,epoll_wait还会再次向应用程序通告此事件,直到该事件被处理。
ET工作模式:当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait调用将不再向应用程序通知这一事件。
注:每个使用ET模式的文件描述符都应该是非阻塞的。如果文件描述符是阻塞的,那么读或写操作将会因为没有后续的事件而一直处于阻塞状态(饥渴状态)。
EPOLLONESHOT事件
对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或者异常事件,且只触发一次,除非使用epoll_ctl函数重置该文件描述符上注册的EPOLLONESHOT事件。
注册了EPOLLONESHOT事件的socket一旦被某个线程处理完毕,该线程就应该立即重置这个socket上的EPOLLONESHOT事件,以确保这个socket下一次可读时,其EPOLLIN事件能被触发,进而让其他工作线程有机会继续处理这个socket。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)