我有一个多线程epoll服务器。我创建了一个epollfd,然后我将有X个线程处于休眠状态,用epoll_wait()
等待SAMEepollfd中的任何事件。
现在我的问题是:当N>1&;N<十、
到目前为止,我一直使用Linux特定的eventfd功能,它只使用1个线程就可以很好地工作,但现在有多个线程在等待SAMEepoll-fd,出现了一个问题:
案例1)LT:如果我用"级别触发"模式添加我的eventfd,ALL线程将在我写入eventfd时唤醒,这就是级别触发模式的工作方式:一旦fd改变状态,让我们唤醒所有线程。
N=X
情况2)ET:如果我用"边缘触发"模式添加我的事件fd,当我向事件fd写入时,ONLY 1线程将唤醒,这就是边缘触发模式的工作方式:在我从read(eventfd, ...);
接收EAGAIN
之前,不再发生epollfd事件。
N=1
情况3)我也尝试过一个自管道技巧,向管道写N次会唤醒N个线程。相反,它不起作用:它不可靠,有时一个线程从管道中读取2个"令牌",有时读取1个或3个。
N=随机
在我尝试过的所有情况下,我都不能只得到N=N,我不能只唤醒N个线程,而是1或all或RANDOM。我错过了什么?有什么想法吗?注意:我还尝试了eventfd特定的EFD_SEMAPHORE
标志,但没有任何帮助。
根据eventfd手册页面。
文件描述符是可读的(select(2)readfds论点如果计数器具有值大于0。
通过创建带有EFD_SEMAPHORE
标志的事件fd:
(如果)eventfd计数器具有非零值,则read(2)返回包含值1的8个字节,并且计数器的值递减1。
使用信号量(EFD_SEMAPHORE
标志)NONBLOCK(EFD_NONBLOCK
标志)eventfd并等待电平触发的epoll()
或正常的poll()
。
使用eventfd_write(fd, N)
编写N线程你想醒来。
当线程唤醒时,执行read()
。如果如果出现EAGAIN
错误,您可以返回睡眠因为N已成功读取,并且因此N线程知道他们必须保持清醒。
缺点
所有线索都醒了(雷鸣般的群体问题)。
由于您主要要退出唤醒线程,正如您在评论中所澄清的,以下是您可以做的:
- 使用ET和自管
- 将数字N写入自管道(根据您的喜好,2或4字节int)
- 在epoll_wait()上等待的线程将唤醒,从管道中读取数字N,如果它>1,则将其递减并写入自身管道,然后退出
-
这会唤醒第二个线程,从管道中读取数字(现在为N-1)。如果它>1,则递减它并写入self-pipe并退出。…
-
依此类推,在某个时刻,最后一个线程从管道中读取1。该线程应该退出,但不再写入管道。