0

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

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

到目前为止,我一直在使用 Linux 特定的 eventfd 工具,它只使用 1 个线程就可以很好地工作,但是现在有多个线程等待SAME epoll fd,出现了一个问题:

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

N = X

案例 2) ET:如果我使用“边缘触发”模式添加我的 eventfd,当我写入 eventfd 时只有 1 个线程会唤醒,这就是边缘触发模式的工作原理:在我收到EAGAIN来自read(eventfd, ...);.

N = 1

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

N = 随机

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

4

2 回答 2

1

根据eventfd手册页。


如果计数器的值大于 0 ,则文件描述符是可读的(select(2) readfds 参数;poll(2) POLLIN 标志)。

通过创建带有EFD_SEMAPHORE标志的 eventfd:

(如果) eventfd 计数器有一个非零值,那么 read(2) 返回包含值 1 的 8 个字节,并且计数器的值减 1。


使用 semaphored ( EFD_SEMAPHOREflag)、NONBLOCK ( EFD_NONBLOCKflag) eventfd 并等待 level-triggeredepoll()或 normal poll()

随着eventfd_write(fd, N)您编写要唤醒的N个线程。

当线程唤醒时,您执行read(). 如果EAGAIN出现错误,您可能会重新进入睡眠状态,因为已经完成N次成功读取,因此N线程知道它们必须保持清醒。

缺点

所有线程都被唤醒(雷鸣般的羊群问题)。

于 2018-03-11T20:13:17.650 回答
0

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

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

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

于 2015-03-10T15:17:20.213 回答