繁体   English   中英

在 WinAPI 中重置信号量计数器

[英]Reset counter of semaphore in WinAPI

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

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

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

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

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

字面回答:不,您不能以原子方式重置信号量。


在单一消费者的情况下,您可能一开始就不应该使用信号量。 自动重置事件就足够了,消费者循环如下:

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

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

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


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

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

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


在多消费者情况下,一种简单的方法是将 SRW 锁(如 Hans 建议)与信号量结合使用:

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

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

  • 要清空队列,获得一个写者(“独占”)锁,清除队列,反复等待信号量直到它为空,释放锁。

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

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

while (WaitForSingleObject(handle, 0) == WAIT_OBJECT_0);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM