简体   繁体   English

在 WinAPI 中重置信号量计数器

[英]Reset counter of semaphore in WinAPI

I have a queue with one consumer and multiple producers.我有一个包含一个消费者和多个生产者的队列。 It is based on Semaphore created with CreateSemaphore() .它基于使用CreateSemaphore()创建的信号量。

While queue is empty Semaphore is set to zero.当队列为空时,信号量设置为零。 Producer puts message to a queue and increments counter so consumer waits for item in a queue.生产者将消息放入队列并增加计数器,以便消费者等待队列中的项目。

There is a case that requires to clear queue.有一种情况需要清除队列。 That means that semaphore counter must be reset to 0 .这意味着信号量计数器必须重置为0

Unfortunately, I did not found an option on MSDN to reset counter.不幸的是,我在 MSDN 上没有找到重置计数器的选项。 Usage of WaitForSingleObject() while counter is not zeroed creates racing conditions, so doesn't seem to be an option.在计数器未清零时使用WaitForSingleObject()会产生竞争条件,因此似乎不是一种选择。

Is there any another way to reset semaphore counter in Windows?有没有其他方法可以在 Windows 中重置信号量计数器?

Literal answer: no, you cannot atomically reset a semaphore.字面回答:不,您不能以原子方式重置信号量。


In the single consumer case, you probably shouldn't be using a semaphore in the first place.在单一消费者的情况下,您可能一开始就不应该使用信号量。 An auto-reset event is sufficient, with a consumer loop like this:自动重置事件就足够了,消费者循环如下:

  • try to pop an item from the queue尝试从队列中弹出一个项目
  • if successful, process it;如果成功,处理它; return to top of loop返回循环顶部
  • if the queue is empty, wait on the event, then return to top of loop如果队列为空,则等待事件,然后返回循环顶部

With this logic, you can clear the queue without needing to do anything to the event.使用此逻辑,您无需对事件执行任何操作即可清除队列。

Note that if the producer/consumer logic can be integrated with the queue's own locking mechanism, it may be more efficient to use a condition variable.请注意,如果生产者/消费者逻辑可以与队列自己的锁定机制集成,则使用条件变量可能更有效。


A more generic option for the single consumer case (assuming a FIFO queue) is to set a flag for the consumer, then add a guard message at the end of the queue.对于单个消费者情况(假设一个 FIFO 队列),一个更通用的选项是为消费者设置一个标志,然后在队列的末尾添加一个保护消息。

Whenever the consumer takes a message off the queue, it can check the flag, and if set, discard all messages until the guard message arrives.每当消费者从队列中取出消息时,它可以检查标志,如果设置,则丢弃所有消息,直到保护消息到达。

(If another queue clear might be attempted while the consumer is still processing a previous one, then you need some additional locking. This can just be an auto-reset event that is set initially, waited on before setting the flag, and then set again by the consumer when it sees the guard message.) (如果在消费者仍在处理前一个队列时可能尝试另一个队列清除,那么您需要一些额外的锁定。这可以是最初设置的自动重置事件,在设置标志之前等待,然后再次设置由消费者在看到保护消息时执行。)


In the multiple consumer case, one simple approach is to use a SRW lock (as Hans suggested) in combination with a semaphore:在多消费者情况下,一种简单的方法是将 SRW 锁(如 Hans 建议)与信号量结合使用:

  • To add an item to the queue, obtain a reader ("shared") lock, add the item, increment the semaphore, release the lock.要将项目添加到队列中,请获取读取器(“共享”)锁,添加项目,增加信号量,释放锁。

  • To remove an item from the queue, wait for the semaphore, obtain a reader ("shared") lock, remove the item, release the lock.要从队列中删除项目,请等待信号量,获取读取器(“共享”)锁,删除项目,释放锁。

  • To empty the queue, obtain a writer ("exclusive") lock, clear out the queue, repeatedly wait for the semaphore until it is empty, release the lock.要清空队列,获得一个写者(“独占”)锁,清除队列,反复等待信号量直到它为空,释放锁。

In rare instances, at the point where you obtained the writer lock, one of the consumer threads will have just decremented the semaphore and be about to try obtaining a reader lock.在极少数情况下,在您获得写入者锁时,其中一个消费者线程将刚刚递减信号量并准备尝试获得读取者锁。 When that thread finally gets the lock, it will find that the queue is empty.当该线程最终获得锁时,它会发现队列为空。 This is harmless, though if you wanted to, you could detect threads in this state (by noticing that the number of items removed from the queue was greater than the number of times you decremented the semaphore) and leave one or more dummy items in the queue for them to find and discard.这是无害的,但如果您愿意,您可以检测处于此状态的线程(通过注意到从队列中删除的项目数大于您递减信号量的次数)并在队列中留下一个或多个虚拟项目排队等待他们寻找和丢弃。

How about calling WaitForSingleObject(semaphore, 0) to attempt to obtain the semaphore with 0 waiting time?如何调用 WaitForSingleObject(semaphore, 0) 尝试获取等待时间为 0 的信号量? This effectively resets a single count semaphore.这有效地重置了单个计数信号量。 You may need to repeat the call if has multiple counts.如果有多个计数,您可能需要重复调​​用。

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

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

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