多线程epoll服务器:唤醒N个线程睡在同一个epoll fd上

时间:2015-02-16 11:56:22

标签: linux multithreading io epoll epollet

我有一个多线程的epoll服务器。 我创建一个epoll fd,然后我将让X线程处于休眠状态,等待来自 SAME epoll fd的任何事件的epoll_wait()

现在我的问题是:如何唤醒N个线程,N> 1&& N< X?

到目前为止,我已经使用了Linux特定的eventfd工具,并且它只有1个线程工作得很好,但现在有多个线程在等待 SAME epoll fd,出现了一个问题:< / p>

案例1)LT:如果我使用“级别触发”模式添加我的eventfd,当我写入eventfd时,所有线程将被唤醒,这就是级别触发模式的工作原理:一次fd改变状态让我们唤醒所有线程。

N = X

案例2)ET:如果我使用“边缘触发”模式添加我的eventfd,当我写入eventfd时, ONLY 1 线程将被唤醒,这就是边缘触发模式的工作原理:在我从EAGAIN收到read(eventfd, ...);之前,不再发生epollfd事件。

N = 1

案例3)我也尝试过自管道技巧,并且向管道写N次会唤醒N个线程。相反它不起作用:它不可靠,有时一个线程从管道中读取2个“令牌”,有时为1或3。

N = RANDOM

在我试过的所有情况下,我不能只得到N = N,我不能只唤醒N个线程,而是1或ALL,或RANDOM。 我错过了什么?有什么想法吗? 注意:我还尝试了eventfd特定的EFD_SEMAPHORE标志,没有任何帮助。

2 个答案:

答案 0 :(得分:1)

根据prefetching手册页。

  

文件描述符是可读的(select(2)readfds   参数;民意调查(2)POLLIN标志)如果计数器有   值大于0

通过使用EFD_NONBLOCK标志创建eventfd:

  

(if)eventfd计数器具有非零值,然后是a   read(2)返回包含值1的8个字节,和   计数器的值减1。

使用信号量(epoll()标志),NONBLOCK (poll()标志)eventfd并等待 级别触发eventfd_write(fd, N)或普通read()

使用EAGAIN编写 N 个帖子 你想醒醒。

线程唤醒时,执行MAIL_DRIVER=smtp。如果 如果出现MAIL_HOST=mail.mydomain.tld错误,您可能会重新入睡 因为 N 已成功完成读取 因此 N 线程知道他们必须保持清醒。

缺点

唤醒所有线程(eventfd问题)。

答案 1 :(得分:0)

由于您主要是要退出唤醒线程,正如您在评论中澄清的那样,您可以执行以下操作:

  • 使用ET和自管道。
  • 将数字N写入自管道(如您所愿,2或4字节为int)
  • 等待epoll_wait()的线程唤醒,从管道读取数字N,如果它是&gt; 1,递减它并写入自管道,然后退出
  • 这会唤醒第二个线程,它从管道读取数字(现在为N-1)。如果是> 1,减少它并写入自管道并退出。 ...

  • 依此类推,最后一个帖子从管道读取1。该线程应该退出但不再写入管道。