2012-02-28 72 views
1

我目前使用ManualResetEvent爲單個線程等待多個線程添加一些東西到一個線程管理器的隊列。如果線程管理器使用手動重置事件接收到信號,它將使添加的項目出列並進行進一步處理。我唯一的問題是,如果有多個設置被觸發,那麼其他隊列項目將不會被處理。 (見B點ManualResetEvent大小檢查是否足以等待多個線程?

while (IsThreadRunning) 
{ 
    // A: My workaround is to check if queue has item, if not then wait for other thread to set the event 
    if (DataQueue.Count <= 0) 
    { 
     ResetEvent.WaitOne(); 
    } 

    // B: At this point two thread added item to the queue and did ResetEvent.Set() twice. 
    if (DataQueue.Count > 0) 
    { 
     DataQueue.Dequeue(); 
    } 

    // Reset the event to avoid processor hog 
    ResetEvent.Reset(); 
} 

我就在這裏解決方法是在A點加入隊列大小條件。 有沒有另一種方法來執行此操作以避免死鎖?

注意:關於使用ManualResetEvent的例子的常見場景是有多個線程在單個線程上等待(ManualResetEvent.Wait)事件,但這裏有多個線程觸發(ManualResetEvent.Set)事件。是否有其他課程用於此場景?

+1

爲什麼不簡單地改變你的第二,如果一段時間? – 2012-02-28 01:40:02

回答

1

您可以處理隊列中的所有項目(如果有),然後等待事件發出信號。

當發出事件信號時,立即將其重置。

如果事件在處理隊列中的最後一個項目後發出信號,則會發生的最壞情況是您將檢查隊列並將其清空。

while (IsThreadRunning) 
{ 
    while (DataQueue.Count > 0) 
    { 
    DataQueue.Dequeue(); 
    } 
    ResetEvent.WaitOne(); 
    ResetEvent.Reset(); 
} 
1

立即轉儲手動重置事件。不要爲此使用任何事件。使用信號量和鎖。在push方法中,鎖定隊列,將對象推入隊列,退出鎖定語句塊,然後發出信號。在pop方法中,等待信號量,然後鎖定隊列,彈出對象並退出鎖定語句塊。

這就是如果你真的想自制生產者 - 消費者隊列。如果你想要一個已經工作的隊列,看看BlockingCollection類。

+0

這是你的嗎? http://www.dijksterhuis.org/using-semaphores-in-c/ – Nap 2012-02-28 02:26:37

+0

@Nap - 不。使用隊列鎖和信號量(如果隊列有界,則有2個信號量)是實現生產者 - 消費者隊列的'計算機科學101'方式。我不知道開發人員如何使用事件而不是信號量來尋找具有計數器的同步機制。 – 2012-02-28 09:00:52