在WinAPI中重置信号量计数器

时间:2015-05-03 15:14:53

标签: c winapi visual-c++ semaphore

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

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

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

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

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

2 个答案:

答案 0 :(得分:1)

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

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

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

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

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

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

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

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

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

  • 要将项目添加到队列,请获取阅读器(“共享”)锁定,添加项目,增加信号量,释放锁定。

  • 要从队列中删除项目,请等待信号量,获取阅读器(“共享”)锁定,删除项目,释放锁定。

  • 要清空队列,获取编写器(“独占”)锁定,清除队列,反复等待信号量直到它为空,释放锁定。

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

答案 1 :(得分:0)

如何调用WaitForSingleObject(semaphore,0)尝试获取等待时间为0的信号量?这样可以有效地重置单个计数信号量。如果有多个计数,则可能需要重复通话。