在WinAPI中重置信号量计数器

问题描述 投票:1回答:2

我有一个消费者和多个生产者的队列。它基于使用CreateSemaphore()创建的信号量。

队列为空时,信号量设置为零。生产者将消息放入队列并递增计数器,以便消费者等待队列中的项目。

有一种情况需要清除队列。这意味着信号量计数器必须重置为0

不幸的是,我没有在MSDN上找到重置计数器的选项。当计数器未归零时使用WaitForSingleObject()会产生竞赛条件,因此似乎不是一种选择。

有没有其他方法可以重置Windows中的信号量计数器?

c winapi visual-c++ semaphore
2个回答
1
投票

字面答案:不,你不能自动重置信号量。


在单个消费者案例中,您可能不应该首先使用信号量。自动重置事件就足够了,消费者循环如下:

  • 尝试从队列中弹出一个项目
  • 如果成功,处理它;回到循环的顶部
  • 如果队列为空,请等待事件,然后返回到循环顶部

使用此逻辑,您可以清除队列而无需对事件执行任何操作。

请注意,如果生产者/消费者逻辑可以与队列自己的锁定机制集成,则使用条件变量可能更有效。


单个消费者案例(假设FIFO队列)的更通用选项是为消费者设置标志,然后在队列末尾添加保护消息。

每当消费者从队列中取消消息时,它就可以检查该标志,如果设置,则丢弃所有消息,直到保护消息到达。

(如果在消费者仍处理前一个队列时可能会尝试清除另一个队列,那么您需要一些额外的锁定。这可能只是一个自动重置事件,最初设置,在设置标志之前等待,然后再次设置当消费者看到警卫信息时。


在多个消费者案例中,一种简单的方法是使用SRW锁(如Hans所建议的)与信号量结合使用:

  • 要将项添加到队列,请获取读取器(“共享”)锁,添加项,增加信号量,释放锁。
  • 要从队列中删除项目,请等待信号量,获取读取器(“共享”)锁定,删除项目,释放锁定。
  • 要清空队列,获取编写器(“独占”)锁定,清除队列,反复等待信号量直到它为空,释放锁定。

在极少数情况下,在您获得写入程序锁定的位置,其中一个使用者线程将刚刚递减信号量并即将尝试获取读取器锁定。当该线程最终获得锁定时,它将发现该队列为空。这是无害的,但是如果你想,你可以检测到这种状态下的线程(通过注意从队列中删除的项目数大于你递减信号量的次数)并留下一个或多个虚拟项目。排队等待他们查找和丢弃。


0
投票

如何调用WaitForSingleObject(semaphore,0)来尝试获取0等待时间的信号量?这有效地重置了单个计数信号量。如果有多个计数,您可能需要重复呼叫。

© www.soinside.com 2019 - 2024. All rights reserved.