下面内容来自linux man page
The epoll event distribution interface is able to behave both as edge-triggered (ET) and as level-triggered (LT). The difference between he two mechanisms can be described as follows. Suppose that this scenario happens:
1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
2. A pipe writer writes 2 kB of data on the write side of the pipe.
3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
4. The pipe reader reads 1 kB of data from rfd.
5. A call to epoll_wait(2) is done.
If the rfd file descriptor has been added to the epoll interface using the EPOLLET (edge-triggered) flag, the call to epoll_wait(2) done in step 5 will probably hang despite the available data still present in the file input buffer; meanwhile the remote peer might be expecting a response based on the data it already sent. The reason for this is that edge-triggered mode delivers events only when changes occur on the monitored file descriptor. So, in step 5 the caller might end up waiting for some data that is already present inside the input buffer. In the above example, an event on rfd will be generated because of the write done in 2 and the event is consumed in 3. Since theread operation done in 4 does not consume the whole buffer data, the call to epoll_wait(2) done in step 5 might block indefinitely.
简单来说,如果使用ET模式,对于同一个事件,内核只会上报一次。如果代码没有读取完所有可读取的数据,然后继续调用epoll_wait那么是不会收到事件的。ET模式一般要设定成setnonblocking模式,并且等到读取数据返回EAGAIN或者
如果使用LT模式,则调用epoll_wait后会继续有事件触发。LT模式与poll保持一样的语义,区别是比poll的性能更好一些。
某一个文件,可能来的数据非常多,持续的多,那么这个文件会不停的进行read(按照我们前面说的返回EAGAN或者返回小于指定大小的思路)。由于整个运行时单线程的,那么其他fd就会一直等待,造成了所谓的饥饿现象
epoll的饥饿模式如何避免?linux man page中给出的答案时,不直接在epoll_wait返回后直接读取数据,而是将可读的fd放到一个list里面。然后再对这个list中的fd分别执行read,可以通过限制每个fd一次read的字节数来控制切换到其他fd,当一个fd 读完后从list删除掉。
处理使用 epoll ET 模式下文件描述符出现饥饿的情况_epoll wait防饥饿-CSDN博客
/proc/sys/fs/epoll/max_user_watches 中记录系统范围内,限制加入到epoll中的句柄数,实际上是限制句柄相关的内存(64位下160字节,32位下90字节)最多只能占用内存的4%。
注意: