2015-05-03 26 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