2013-01-09 60 views
1

这是继续问题14221339.epoll是否有线程安全问题?

我有一个在epoll_wait()循环内运行的线程池。

外部线程调用epoll_ctl(),并增加了与

(EPOLLET | EPOLLONESHOT | EPOLLIN)一个监听套接字。

当线程池只有一个线程时,它间歇性地无法接收第一个(也是唯一)连接尝试的EPOLLIN事件。如果我将线程池增加到两个,它几乎总是无法收到EPOLLIN事件。

我的理解是,epoll API是线程安全的,但是这个观察似乎表明了其他情况。

回答

5

使用边缘触发的语义,不正确的调用序列可能会导致竞争条件。有三个系统调用涉及:

  1. epoll_ctl()以激活通知(并且如果使用 EPOLLONESHOT激活)。
  2. epoll_wait()接收通知。
  3. 系统输入:在循环中读取()/ recv()/ accept(),直到错误EAGAIN。

如果以该顺序执行(重复),则#3和#1之间的竞争是可能的:当内核中的输入事件发生在EAGAIN已被返回但可以对epoll_ctl()执行操作之前。通常,重新激活需要在I/O之前完成。

  1. epoll_ctl()以激活通知(并且如果使用 EPOLLONESHOT重新激活)。
  2. 系统输入:在循环中读取()/ recv()/ accept(),直到错误EAGAIN。
  3. epoll_wait()接收通知。

(显然,I/O需求是不可阻挡。)

+1

我发现这个问题,它实际上已经无关epoll的。我的应用程序是用C++编写的,线程池的创建包含一个带有可变参数和std :: bind的递归模板函数。发生了一些奇怪的竞态条件,其中std :: function对象被清除,所以线程永远不会进入epoll_wait()循环。 – user1715664

+1

很高兴你解决了这个问题! – arayq2

+0

@ arayq2你确定该电话订单吗?我从来没有看到任何epoll相关的顺序调用它们?我有一个类似的问题[这里](http://stackoverflow.com/questions/33885439/epoll-with-edge-triggered-and-oneshot-only-reports-once)。手册页建议,一旦fd被重新启用,如果它能够符合标志的标准,即使在等待之后调用ctl,它也会触发事件。任何额外的信息,你可以给这个将是伟大的:) – nathansizemore