如何为 3 个不同的事件(信号量、pthread 条件和阻塞套接字接收)阻塞单个线程?
Posted
技术标签:
【中文标题】如何为 3 个不同的事件(信号量、pthread 条件和阻塞套接字接收)阻塞单个线程?【英文标题】:How can I block a single thread for 3 different events (semaphore, pthread condition, and blocking socket recv)? 【发布时间】:2017-09-29 15:31:00 【问题描述】:我有一个多线程系统,其中一个主线程必须在阻塞状态下等待以下 4 个事件之一的发生:
-
进程间信号量 (sem_wait())
pthread 条件 (pthread_cond_wait())
来自套接字的recv()
超时到期
理想情况下,我想要一种在发生上述任何情况时解除阻塞主线程的机制,例如带有适当超时参数的 ppoll() 。由于对 CPU 使用率的影响,非阻塞和轮询是不可能的,而由于延迟增加,不同的事件阻塞不同的线程并不理想(一个线程从一个事件中解除阻塞最终应该唤醒主一)。
如果有帮助,代码将几乎完全在 Linux 下使用 gcc 工具链编译,但如果可能的话,一些可移植性会很好。
提前感谢您的任何建议
【问题讨论】:
你能编辑后台线程的代码吗?也就是说,您可以在后台线程中修改信号量和条件变量的任何位置添加更多代码吗? @bnaecker 我可以访问线程内同步代码(本质上是通知 pthread 条件变量的线程),但不能访问进程间信号量,因为 sem_post() 在这个信号量上的进程我正在等待的是第 3 方,不在我的控制范围内。 【参考方案1】:在类 Unix 系统上等待多种类型对象的机制不是很好。总的来说,这个想法是尽可能使用 IPC 的文件描述符,而不是多种不同的 IPC 机制。
从您的评论看来,您可以编辑或更改条件变量,但不能编辑或更改发出信号量的代码。所以我建议如下。
将条件变量更改为管道(以提高可移植性)或eventfd(2)
对象(特定于Linux)。每当它想向主线程发出信号时,通知线程都会写入管道。这将允许您在该管道和套接字的主线程中使用 select(2)
或 poll(2)
或其他任何内容。
因为你被信号量困住了,我认为最好的选择是创建另一个线程,其唯一目的是使用sem_wait()
等待信号量,然后写入另一个管道或eventfd(2)
对象无论进程在做什么sem_post()
都会通知它。在主线程中,只需将这个其他文件描述符添加到您的 select(2)
集合中。
因此您将拥有三个描述符:一个用于套接字,一个用于代替条件变量,一个用于在信号量递增时写入。然后,您可以使用您最喜欢的 I/O 多路复用方法等待所有三个,并直接包含您想要的任何超时。
【讨论】:
谢谢。用管道替换 pthread 条件很简单。我们使用条件向主线程发出作业结束的信号,因此管道可以轻松完成此操作。但是,我想知道,在从 pthread cond_wait 切换到管道上的阻塞 recv 时,我是否应该期望任何性能(意味着延迟)损失? 没关系,在这里找到了这个非常彻底的分析:***.com/questions/7979164/…以上是关于如何为 3 个不同的事件(信号量、pthread 条件和阻塞套接字接收)阻塞单个线程?的主要内容,如果未能解决你的问题,请参考以下文章
如何为 recyclerView 上的两个不同事件设置监听器?