我有一个消费者和多个生产者的队列。它基于使用CreateSemaphore()
创建的信号量。
队列为空时,信号量设置为零。生产者将消息放入队列并递增计数器,以便消费者等待队列中的项目。
有一种情况需要清除队列。这意味着信号量计数器必须重置为0
。
不幸的是,我没有在MSDN上找到重置计数器的选项。当计数器未归零时使用WaitForSingleObject()
会产生竞赛条件,因此似乎不是一种选择。
有没有其他方法可以重置Windows中的信号量计数器?
字面答案:不,你不能自动重置信号量。
在单个消费者案例中,您可能不应该首先使用信号量。自动重置事件就足够了,消费者循环如下:
使用此逻辑,您可以清除队列而无需对事件执行任何操作。
请注意,如果生产者/消费者逻辑可以与队列自己的锁定机制集成,则使用条件变量可能更有效。
单个消费者案例(假设FIFO队列)的更通用选项是为消费者设置标志,然后在队列末尾添加保护消息。
每当消费者从队列中取消消息时,它就可以检查该标志,如果设置,则丢弃所有消息,直到保护消息到达。
(如果在消费者仍处理前一个队列时可能会尝试清除另一个队列,那么您需要一些额外的锁定。这可能只是一个自动重置事件,最初设置,在设置标志之前等待,然后再次设置当消费者看到警卫信息时。
在多个消费者案例中,一种简单的方法是使用SRW锁(如Hans所建议的)与信号量结合使用:
在极少数情况下,在您获得写入程序锁定的位置,其中一个使用者线程将刚刚递减信号量并即将尝试获取读取器锁定。当该线程最终获得锁定时,它将发现该队列为空。这是无害的,但是如果你想,你可以检测到这种状态下的线程(通过注意从队列中删除的项目数大于你递减信号量的次数)并留下一个或多个虚拟项目。排队等待他们查找和丢弃。
如何调用WaitForSingleObject(semaphore,0)来尝试获取0等待时间的信号量?这有效地重置了单个计数信号量。如果有多个计数,您可能需要重复呼叫。