簡體   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