EPOLLET的用例是什么?

Sha*_*esh 1 linux epoll epollet

epoll在边缘触发模式下是一只奇怪的野兽。它要求该过程跟踪每个受监控FD的最后响应是什么。它要求流程能够无故障地处理所报告的每个事件(否则,我们可能会认为FD实际上没有被边缘触发行为所静音,而是没有报告任何东西)。

什么时候使用epoll这种方式有意义?

Sha*_*esh 5

EPOLLET我知道的主要用例是微线程。

回顾一下-用户空间正在根据要处理的东西的可用性在微线程(我将之称为“光纤”,因为它更短)之间进行上下文切换。这也称为“协作多任务”。

文件描述符的基本处理是通过包装相关的IO函数,如下所示:

ssize_t read(int fd, void *buffer, size_t length) {
  // fd should already be in O_NONBLOCK mode
  while(true) {
    ssize_t result = ::read(fd, buffer, length); // The real read
    if( result!=-1 || (errno!=EAGAIN && errno!=EWOULDBLOCK) )
      return result;

    start_monitoring(fd, READ);
    wait_event();
  }
}
Run Code Online (Sandbox Code Playgroud)

start_monitoring是一项功能,可确保fd对其进行读取可用性监视。wait_event执行上下文切换,直到调度程序重新唤醒该光纤,因为fd现在已有数据可供读取。

通常的实现方法epollEPOLL_CTL_MODfd内部调用start_monitoring来添加监听EPOLLIN,并在epoll报告停止监听的事件之后再次调用EPOLLIN

这意味着read具有可用数据的会在1个系统调用内完成,但返回的读取EAGAIN至少进行 4个系统调用(原始read,两个EPOLL_CTL_MOD,最后read一个成功)。

请注意,以上内容不epoll_wait包括必须进行的操作。我不算数,因为我大胆地假设其他光纤也将被同一系统调用唤醒,因此将其成本全部归因于我们的光纤是不公平的。总而言之,此机制需要4 + x个系统调用,其中x在0到1之间。

降低成本的一种方法是使用EPOLLONESHOT。这样一来,您就无需fd自动进行监控,从而将我们的成本降低到3 + x。更好,但是我们可以做得更好。

输入EPOLLET。前一个fd状态可以是布防或不布防(即-下一个事件是否会触发epoll)。另外,fd当前(在进入时read)可能已经准备好也可能没有。四个州。让我们散布它们。

就绪(无论是否布防):第一次调用read返回数据。1个系统调用。该路径不会更改武装状态,就绪状态取决于我们是否阅读了所有内容。

未准备就绪(无论是否布防):第一次调用readreturn EAGAIN,从而布防了fd。我们wait_event无需执行另一个系统调用就可以入睡。一旦我们醒来,我们就处于未武装模式(就像我们刚刚醒来一样)。因此,我们不需要调用epoll_ctl来禁用对fd的监听。我们称read它返回数据。我们使该功能准备就绪或未准备就绪,但没有武装。

总费用:2 + x。

起步时fd,我们将不得不面对一个虚假的唤醒fd。我们的代码必须处理epoll报告没有光纤正在监听的fd 的情况。在这种情况下,处理只是意味着忽略并继续前进。不会再次虚假报告该FD。