epoll学习笔记:Level-triggered and edge-triggered

Epoll: Level-triggered and edge-triggered

edge-triggered

The epoll event distribution interface is able to behave both as edge-triggered (ET) and as level-triggered (LT). The difference between the 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.

如果文件描述符以EPOLLET的方式添加到epoll用例中。在第5步中,尽管在input buffer中仍然存在数据,但对epoll_wait的调用完成可能会挂起。
与此同时,对面远端可能在对发出的数据等待response。原因在于edge_trigger模式仅仅在监控的文件描述符发生改变时,产生events。所以,第5步中, 在一些数据已经被放进input buffer中时,调用者可能会结束等待。在上面的例子中,因为第2步写数据结束,生成rfd上的事件,然后被第3步处理。由于在第4步中没有处理所有的数据,所以第5步中的epoll_wait可能会无限期阻塞。

使用了EPOLLET的应用应该使用非阻塞文件描述符去避免使用阻塞读写时,饿死处理多个文件描述符的task。

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 only delivers events 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 the read operation done in 4 does not consume the whole buffer data, the call to epoll_wait(2) done in step 5 might block indefinitely.
An application that employs the EPOLLET flag should use nonblocking file descriptors to avoid having a blocking read or write starve a task that is handling multiple file descriptors. The suggested way to use epoll as an edge-triggered (EPOLLET) interface is as follows:

建议使用EPOLLET的方式如下:

  1. 使用非阻塞接口

  2. 只有在read和write返回 EAGAIN 时再执行event的等待操作
    by waiting for an event only after read(2) or write(2) return EAGAIN.

Level-triggered

当使用level-triggered(默认,当未使用EPOLLET时),epoll仅仅就是个更快的poll。并且可以用于poll使用的场景中,因为它们共用一样的语句。
By contrast, when used as a level-triggered interface (the default, when EPOLLET is not specified), epoll is simply a faster poll(2), and can be used wherever the latter is used since it shares the same semantics.

Since even with edge-triggered epoll, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to specify the EPOLLONESHOT flag, to tell epoll to disable the associated file descriptor after the receipt of an event with epoll_wait(2). When the EPOLLONESHOT flag is specified, it is the caller's responsibility to rearm the file descriptor using epoll_ctl(2) with EPOLL_CTL_MOD.

The following interfaces can be used to limit the amount of kernel memory consumed by epoll:
/proc/sys/fs/epoll/max_user_watches (since Linux 2.6.28)
This specifies a limit on the total number of file descriptors that a user can register across all epoll instances on the system. The limit is per real user ID. Each registered file descriptor costs roughly 90 bytes on a 32-bit kernel, and roughly 160 bytes on a 64-bit kernel. Currently, the default value for max_user_watches is 1/25 (4%) of the available low memory, divided by the registration cost in bytes.

posted @   ug_难  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示