线程之间的信号
Posted
技术标签:
【中文标题】线程之间的信号【英文标题】:Signaling between threads 【发布时间】:2013-09-21 18:11:21 【问题描述】:应用程序设计
我有一个 C++ 应用程序,它有一个生产者线程、多个队列(在运行时创建)和消费者线程。
生产者线程通过 Tcp/Ip 获取数据并放入相应的队列(例如,如果数据是 A 类型并放入队列 A)。
消费者线程当前从1-n循环队列以处理来自每个队列的数据。
根据要求,无需跟踪上次更新或最少更新的队列。只要有任何队列被更新,消费者就应该处理 1 - n 个队列。
如果任何队列的大小超过定义的限制,生产者线程将在插入新项目之前弹出第一个项目(以管理队列大小)。
线程之间的资源同步和信令:
在这个实现中,消费者线程应该休眠,直到没有队列有来自侦听器的数据。只有当生产者将数据放入任一队列时,消费者线程才会唤醒。
使用互斥锁在 2 个线程之间同步多个队列。 每当生产者将数据放入任何队列时,都会在线程之间实现事件信号以唤醒消费者线程。
然而,这种唤醒消费者线程的信号方式,尽管任何队列中有数据,消费者仍有可能进入睡眠状态。
问题:
让我们以这个场景为例,假设消费者正在处理第 n 个队列的数据;同时,生产者有可能将数据放入 n-1、n-2 队列,并且由于消费者处于清醒状态并正在处理第 n 个数据,因此信令无效。一旦消费者处理完第n个队列数据,它就会休眠,并且在监听器给出任何进一步的信号之前,n-1,n-2中的数据将不会被处理。
我们如何解决这种情况? 人们还建议使用信号量。信号量与这种情况相关吗?
提前致谢。
【问题讨论】:
你怎么看?你的解决方案是什么? 也许信号量是不够的,因为消费者仍然没有得到信息来重新扫描更改/插入的项目。它只是得到 hios 标志:轮到你了。您可以使用消费者每次读取的共享变量,它完成一个队列项目(比如说最后一个),然后检查一个由生产者设置的变量,它应该从头开始再次检查队列.如果是这样,您可能需要什么- 【参考方案1】:这是 C++11 std::condition_variable
的经典示例。
这种情况下的条件是消耗性资源的可用性。如果消费者线程耗尽工作,他wait
s 在条件变量上有效地让他进入睡眠状态。每次插入队列后的生产者notify
s。必须小心安排锁定,以使队列上的争用保持最小,同时仍然避免消费者错过通知并进入睡眠但工作可用的情况。
【讨论】:
【参考方案2】:信号量可以工作,是的。
但我不完全确定它是否有必要。听起来您的问题纯粹是因为消费者线程在处理队列 N 后无法环回。它应该在连续看到 N empty 队列后进入睡眠状态,同时持有互斥锁以确保同时没有添加任何条目。
当然,一直持有该互斥体是大材小用。相反,您应该继续循环,一一清空队列并计算您看到的空队列数量。一旦您连续看到 N 个空队列,请使用互斥锁,这样您就知道不能添加新条目,然后重新检查。
这确实取决于您的信号机制。强大的信号机制允许您在线程进入对该信号的检查之前发出信号。这是必要的,因为否则您会遇到竞争条件。
【讨论】:
【参考方案3】:您可以使用select
并在由信号生成的文件描述符上等待它 -> 这样它就可以等待超时(选择有它们)并在收到信号时唤醒(信号必须被屏蔽和阻塞)。当signalfd
(查看man signalfd
)可读时,您可以从中读取struct signalfd_siginfo
并检查ssi_signo
的信号编号(如果它是您用于通信的信号编号)。
【讨论】:
以上是关于线程之间的信号的主要内容,如果未能解决你的问题,请参考以下文章
线程之间灵活传递信号(ManualResetEventSlim )