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