是的,生產者(或插入者)將在消費者持有鎖的同時被阻止。請注意,通過調用Monitor.Wait
釋放該鎖,然後在控制流返回給調用者時重新獲取該鎖。所有這些都假設你的製作者試圖獲得相同的鎖定。
作爲一個方面說明,你有消費者編碼的方式效率稍低一些。因爲你有一個continue
陳述,我不得不假設while
循環包裝了lock
,這可能使你的代碼看起來更像以下內容。
object msg = null;
while (msg == null)
{
lock (MsgQueue)
{
if (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
continue;
}
msg = MsgQueue.Dequeue();
}
}
這可能進行重構,以便等待條件的lock
塊內複查。這樣您就不必釋放並重新獲取鎖來執行檢查。
object msg = null;
lock (MsgQueue)
{
while (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
}
msg = MsgQueue.Dequeue();
}
再次,因爲我看到了continue
聲明我假設大家都知道,等待條件必須總是Wait
後複查。但是,如果你不知道這個要求,我會在這裏說明它,因爲它很重要。
如果等待條件沒有被重新檢查,並且有2個或更多的消費者,那麼他們中的一個可以進入鎖內,並將最後一個項目出列。即使其他消費者通過致電Pulse
或PulseAll
從等候隊列移動到就緒隊列,但這仍然可能發生,但它沒有機會在第一個消費者面前重新獲取鎖定。顯然,如果沒有重新檢查,消費者可能會嘗試在空隊列上運行。在生產端是否使用Pulse
或PulseAll
並不重要。仍然存在問題,因爲Monitor
不優先於Enter
之上的Wait
。
更新:
我忘了指出,如果你使用的是.NET 4.0,那麼你可以採取的BlockingCollection這是一個阻塞隊列的實現優勢。對於多個生產者和消費者來說這是安全的,並且如果隊列爲空,則爲你完成所有阻塞。
要驗證您在評論中所說的內容,可以發表一篇關於Enqueue如何的短文嗎? – 2011-06-17 12:49:23
如果你使用的是.Net 4.0,你可以在這裏使用`ConcurrentQueue`,參見http://msdn.microsoft.com/en-us/library/dd267265.aspx – 2011-06-17 15:20:19
我建議你使用[BlockingCollection](http:如果C#4.0或隊列與[AutoRestEvent](http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent。 aspx)檢查[這在stacoverflow](http://stackoverflow.com/questions/6397566/multithreaded-net-queue-problems-c/6404581#6404581) – 2011-06-20 04:07:24