2015-05-03 27 views
1

我有一个消费者和多个生产者的队列。它基于用CreateSemaphore()创建的信号量。重置WinAPI中的信号量计数器

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

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

不幸的是,我没有在MSDN上找到重置计数器的选项。使用WaitForSingleObject()而柜台没有归零创造竞速条件,所以似乎不是一个选项。

是否有任何其他方式来重置Windows中的信号量计数器?

+0

当然,如果你只使用信号量,那就是种族。它不能完成工作,所以不要使用它,请使用[内置支持](https://msdn.microsoft.com/en-us/library/windows/desktop/ms681930%28v=vs .85%29.aspx) –

+2

要清除这样的队列,首先必须确保没有更多项目被推送到它。之后,你可以弹出所有现有的物品并销毁它们。 MSDN上没有选项来重置计数器,因为它不是信号量的受支持操作,也不是。 –

+0

@rcgldr'设置线程优先级更高以防止生产者线程运行'在具有多个核心的计算机上无法可靠工作,因为生产者threa \ ds可能无论如何都可以运行。由于页面错误可以允许生产者线程运行,所以它不能在一个内核上运行。 –

回答

1

直接回答:不,你不能自动重置信号量。


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

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

的顶部,这样的逻辑,你可以清除队列,而无需做任何事件。

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


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

每当消费者从队列中取出消息时,它可以检查该标志,如果设置了,则丢弃所有消息,直到保护消息到达。 (如果在消费者仍在处理前一个队列时尝试另一个队列清除,那么您需要一些额外的锁定,这可能只是一个初始设置的自动重置事件,在设置标志之前等待, 。然后由消费者重新设置时,看到在保护消息)


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

  • 将项目添加到queu e,获得读卡器(“共享”)锁定,添加项目,增加信号量,释放锁定。

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

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

在极少数情况下,在您获得作家锁,消费者一个线程将具有点只是减少信号灯,并准备尝试获取读锁。当线程最终获得锁定时,它会发现队列是空的。这是无害的,但如果你愿意的话,你可以在这个状态下检测线程(注意从队列中删除的项目数量大于你减少信号量的次数),并在其中留下一个或多个虚拟项目排队让他们找到并丢弃。

+0

一旦生产者获得了独占锁定SRW,然后它可以自由地在队列中聚会。不需要额外的信号量。 –

+0

@HansPassant:信号量使消费者可以在队列为空时有效地等待。我想不出有什么办法可以用SRW来做到这一点。 (另外,我假设队列本身已经是线程安全的;在这个模型中,信号量和SRW都不能保护它。) –

+0

@HarryJohnston - 只有一个消费者线程,但是有多个生产者。生产者内部的排序没有解释。我假设有一个免费的消息池,制作者从中提取消息并且消费者返回。如果任何生产者已经从空闲池中检索到消息,但目前正在等待与共享锁无关的其他事件,则存在潜在问题。 – rcgldr