EPOLLET的用例是什么?

时间:2017-10-08 16:32:51

标签: linux epoll epollet

边缘触发模式下的

epoll是一个奇怪的野兽。它要求该过程跟踪每个受监视FD的最后响应。它要求流程尽可能地处理报告的每个事件(否则我们可能会认为FD没有报告任何事情,而事实上,它被边缘触发行为静音)。

何时以这种方式使用epoll是有意义的?

1 个答案:

答案 0 :(得分:4)

我所知道的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();
  }
}

start_monitoring是一个函数,可确保监视fd的读取可用性。 wait_event执行上下文切换,直到调度程序重新唤醒此光纤,因为fd现在已准备好读取数据。

通过epoll实施此操作的常用方法是在EPOLL_CTL_MOD内的fd上致电start_monitoring以添加对EPOLLIN的监听,并在epoll之后再次已报告该活动停止收听EPOLLIN

这意味着具有可用数据的read将在1次系统调用中完成,但返回EAGAIN的读取将至少 4次系统调用(原始{ {1}},两个read,以及成功的最终EPOLL_CTL_MOD

请注意,上述内容不计入必须发生的read。我不算数,因为我采取了慷慨的假设,其他纤维也将被同一系统调用唤醒,因此将其成本完全归因于我们的光纤是不公平的。总而言之,这种机制需要4 + x系统调用,其中x介于0和1之间。

降低成本的一种方法是使用epoll_wait。这样做会自动从监控中删除EPOLLONESHOT,从而将成本降低到3 + x。更好,但我们可以做得更好。

输入fd。之前的EPOLLET状态可以是武装的或非武装的(即 - 下一个事件是否会触发fd)。此外,fd当前可能会或可能不会(在epoll的入口处)准备好数据。四个州。让我们把它们展开。

就绪(无论是否武装):第一次呼叫read将返回数据。 1系统调用。这条路径不会改变武装状态,准备状态取决于我们是否阅读了所有内容。

未准备好(无论是否武装):第一次呼叫read会返回read,从而武装fd。我们在EAGAIN进入睡眠状态而无需执行另一个系统调用。一旦我们醒来,我们就处于非武装模式(因为我们刚刚醒来)。因此,我们不需要调用wait_event来禁用对fd的监听。我们调用epoll_ctl来返回数据。我们让这个功能准备好或不准备,但是没有武装。

总费用:2 + x。

read开始武装时,每fd我们将面临一次虚假的唤醒。我们的代码必须处理fd报告没有光纤正在侦听的fd的情况。在这种情况下,处理只是意味着忽略并继续前进。 FD不会再被虚假报道。