应用程序设计
我有一个c ++应用程序,它有一个生产者线程,多个队列(在运行时创建)和消费者线程。
生产者线程通过Tcp / Ip获取数据并放入相应的队列(例如,如果数据是类型A并放入队列A中)。
消费者线程当前从1-n循环队列以处理来自每个队列的数据。
根据要求,无需跟踪上次更新或最少更新的队列。只要更新了任何队列,消费者就应该处理1到n个队列。
如果任何队列的大小超过定义的限制,则生产者线程将在插入新项目之前弹出第一个项目(以管理队列大小)。
线程之间的资源同步和信令:
在此实现中,消费者线程应该休眠,直到没有队列具有来自侦听器的数据。只有当生产者将数据放入任何一个队列时,才会唤醒消费者线程。
使用互斥锁在2个线程之间同步多个队列。 在线程之间实现事件信令,以便在生产者将数据放入任何队列时唤醒消费者线程。
然而,这种信号唤醒消费者线程的方式,虽然任何队列中都有数据,但消费者可以睡觉。
问题:
让我们看看这个场景,考虑消费者正在处理第n个队列的数据;同时,生产者有可能将数据放入n-1,n-2队列,并且信令无效,因为消费者处于清醒状态并处理第n个数据。一旦消费者完成对第n个队列数据的处理,它就会休眠,并且在听众给出任何进一步的信号之前,n-1,n-2中的数据将不会被处理。
我们如何解决这个问题? 人们也建议使用半光团。信号量是否与这种情况相关?
提前致谢。
答案 0 :(得分:3)
这是C ++ 11 std::condition_variable
的经典示例。
这种情况下的条件是可消耗资源的可用性。如果消费者线程失去工作,他wait
会在条件变量上有效地让他进入睡眠状态。每次插入队列后的生产者notify
。必须注意以尽可能减少队列争用的方式安排锁定,同时仍然避免消费者错过通知并进入睡眠状态,尽管工作可用。
答案 1 :(得分:1)
信号量会起作用,是的。
但我不确定是否有必要。听起来你的问题纯粹是因为消费者线程在处理队列N之后无法循环回来。它应该在它连续看到N 空队列后才会进入休眠状态,同时持有互斥锁以确保平均时间内没有添加任何条目。
当然,持有该互斥量一直是矫枉过正的。相反,您应该保持循环,逐个清空队列并计算您看到的空队列数。一旦您连续看到N个空队列,请使用互斥锁,这样您就不会添加任何新条目,现在重新检查。
这取决于您的信号机制。强大的信号机制允许您在线程进入该信号的检查之前发出信号。这是必要的,因为否则你有竞争条件。
答案 2 :(得分:0)
您可以使用select
并在信号 - >>的文件描述符上等待它所以它可以等待超时(选择它们)并在接收到信号时唤醒(信号必须被屏蔽和阻止)。当signalfd
(外观man signalfd
)可读时,您可以从中读取struct signalfd_siginfo
并检查ssi_signo
的信号编号(如果它是您用于通信的那个)。 / p>