简介
epoll是linux为监听多路IO的状态所实现的方法.
如上图所示,我们前面在介绍eventfd和socketpair的时候,例子用的都是同步阻塞IO的方式.在单一使用的时候,看不出明显的问题.但是当2者同时使用的时候,如果你想同时监听eventfd和socketpair这2路IO状态时,就得创建多一个用户线程B.此时看起来似乎问题也不大,但是如果监听数目达到一定数量级的时候呢?
Linux为解决这种情况,提供了IO多路复用的方法epoll
如上图可以看出,epoll能在同时监听多路IO状态的基础上又不需要额外的线程开销
函数原型
1. 创建epoll文件描述符
SYNOPSIS
1 |
|
RETURN VALUE
On success, these system calls return a nonnegative file descriptor.
On error, -1 is returned, and errno is set to indicate the error.
2. epoll监听文件描述符
SYNOPSIS
1 |
|
RETURN VALUE
When successful, epoll_ctl() returns zero.
When an error occurs, epoll_ctl() returns -1 and errno is set appropriately.
2.1 参数说明
OP | 说明 |
---|---|
EPOLL_CTL_ADD | 添加监听文件描述符 |
EPOLL_CTL_MOD | 修改监听文件描述符的event |
EPOLL_CTL_DEL | 删除监听文件描述符 |
Event Type | 说明 |
---|---|
EPOLLIN | 事件可读 |
EPOLLOUT | 事件可写 |
EPOLLRDHUP | 连接断开(针对socket) |
EPOLLERR | 事件异常 |
EPOLLHUP | 连接断开(全类型文件描述符) |
EPOLLET | 边缘触发 |
EPOLLONESHOT | 事件仅触发一次,如需再次触发,则要再次调用epoll_ctl(op为EPOLL_CTL_MOD) |
EPOLLWAKEUP | 在EPOLLONESHOT和EPOLLET都没设置并且进程拥有CAP_BLOCK_SUSPEND权限的前提下,事件就绪时会申请唤醒锁,阻止系统进入suspend状态,直至事件处理完成再次调用epoll_wait时释放唤醒锁 |
相关结构体
1 | typedef union epoll_data { /* 联合体,联合体内成员无偏移,既共用首地址,该联合体内存占8字节 */ |
2.2 EPOLLET边缘触发和EPOLLLT水平触发区别
1 | // Eventpoll.c(kernel-4.9\fs) |
从上面源码的中,我们举个例子来说明两种触发模式的区别
线程A写了32个字节数据到socket fd触发EPOLLIN事件
线程B从epoll_wait中返回,只读取了10字节数据
EPOLLLT水平触发: 由于未读取完毕,再次调用epoll_wait会直接返回.报告有事件可读
EPOLLET边缘触发: 直接休眠等待下次socket fd的EPOLLIN事件触发(线程A的write动作)
3. epoll等待监听的事件触发
SYNOPSIS
1 |
|
RETURN VALUE
When successful, epoll_wait() returns the number of file descriptors ready for the requested I/O, or zero if no file descriptor became ready during the requested timeout milliseconds.
When an error occurs, epoll_wait() returns -1 and errno is set appropriately.
3.1 参数说明
参数 | 说明 |
---|---|
返回值 | 0代表等待超时,小于0代表错误发生,大于0代表触发的事件个数 |
timeout | 超时时间,毫秒为单位.当为负数时,会一直阻塞等待事件触发 |
maxevents | 最大触发事件的个数(<=events容量) |
events | 事件触发时,该数组会被填充 |
例子
1 | /*本例子的流程为: |
运行结果
1 | generic_arm64_ab:/ # example |
本章完
v1.5.2