我仍然不確定這兩個調用之間的差異。從MSDN開始,Monitor.Enter vs Monitor.Wait
Monitor.Enter(Object)
獲取對指定對象的排他鎖。
Monitor.Wait(Object)
釋放對象的鎖定並阻塞當前線程,直到它重新獲取鎖定。
從這我假設Monitor.Wait是一樣的Monitor.Enter,除了它釋放對象的鎖定之前重新獲取。
當前線程是否必須首先鎖定鎖定?一個不同的線程如何強制釋放一個對象的鎖?爲什麼同一個線程想要重新獲取鎖?
我仍然不確定這兩個調用之間的差異。從MSDN開始,Monitor.Enter vs Monitor.Wait
Monitor.Enter(Object)
獲取對指定對象的排他鎖。
Monitor.Wait(Object)
釋放對象的鎖定並阻塞當前線程,直到它重新獲取鎖定。
從這我假設Monitor.Wait是一樣的Monitor.Enter,除了它釋放對象的鎖定之前重新獲取。
當前線程是否必須首先鎖定鎖定?一個不同的線程如何強制釋放一個對象的鎖?爲什麼同一個線程想要重新獲取鎖?
根據MSDN: Monitor.Wait Method(Object)
SynchronizationLockException:調用線程不擁有指定對象的鎖。
換句話說:你只能調用Monitor.Wait(Object)
,當你已經擁有鎖,而你爲了調用Monitor.Enter(Object)
到獲取鎖。
至於爲什麼需要Monitor.Wait
:如果你的線程意識到,它缺乏繼續執行的信息(例如它正在等待一個信號),你可能想讓其他線程進入臨界區,因爲並非所有的線程都有相同的先決條件。
對於等待的線程可以繼續執行下去,您將需要調用Monitor.Pulse(Object)
或Monitor.PulseAll(Object)
之前釋放鎖(否則,你會得到同樣的異常與Monitor.Wait(Object)
)。
請記住,下一個線程在脈衝之後和鎖定被釋放後獲取鎖定,並不一定是接收脈衝的線程。
另外請記住,接收脈衝不等同於您的條件滿足。您可能還需要等待更長的只是一點點:
// make sure to synchronize this correctly ;)
while (ConditionNotMet)
{
Monitor.Wait(mutex);
if (ConditionNotMet) // We woke up, but our condition is still not met
Monitor.Pulse(mutex); // Perhaps another waiting thread wants to wake up?
}
考慮這個例子:
public class EnterExitExample
{
private object myLock;
private bool running;
private void ThreadProc1()
{
while (running)
{
lock (myLock)
{
// Do stuff here...
}
Thread.Yield();
}
}
private void ThreadProc2()
{
while (running)
{
lock (myLock)
{
// Do other stuff here...
}
Thread.Yield();
}
}
}
現在你有兩個線程,每個線程等待鎖,然後做自己的東西,然後釋放鎖。 lock (myLock)
語法僅適用於Monitor.Enter(myLock)
和Monitor.Exit(myLock)
。
現在讓我們看一個更復雜的例子,其中Wait
和Pulse
發揮作用。
public class PulseWaitExample
{
private Queue<object> queue;
private bool running;
private void ProducerThreadProc()
{
while (running)
{
object produced = ...; // Do production stuff here.
lock (queue)
{
queue.Enqueue(produced);
Monitor.Pulse(queue);
}
}
}
private void ConsumerThreadProc()
{
while (running)
{
object toBeConsumed;
lock (queue)
{
Monitor.Wait(queue);
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}
我們在這裏有什麼?
生產者每當他感覺就產生一個對象。一旦他擁有了,他就獲得隊列鎖定,排隊對象,然後進行Pulse
調用。
與此同時,消費者沒有鎖,他通過致電Wait
離開它。一旦他得到Pulse
這個對象,他將重新鎖定,並做他的消耗的東西。
所以你在這裏是一個直接的線程到線程的通知,有一些消費者要做。如果你不這樣做,你所能做的就是讓消費者繼續對收藏進行投票,如果還有事情要做的話。使用Wait
,你可以確保有。
從其他預期的答案「只有當你已經擁有鎖定時,你才能調用Monitor.Wait(Object)」。當生產者有鎖時,消費者可以調用Monitor.Wait(隊列)嗎? –
製作者在短時間內鎖定了一個'Queue.Enqueue'和一個'Monitor.Pulse'調用所需的時間,後者放棄了鎖定。消費者要麼完全在鎖區之外,這意味着他只需要獲得鎖,稱爲「等待」,由於持續的「脈衝」而立即停止等待,或者他在「等待」呼叫中,使他重新獲得鎖定並且做他的消耗的東西。 –
根據[Monitor.Pulse()](http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx)上的文檔,看起來像是一個等待發生的死鎖:「 Monitor類沒有保持狀態,指示已經調用了Pulse方法,因此,如果在沒有線程正在等待時調用Pulse,則下一個調用Wait塊的線程就像Pulse從未被調用一樣,如果兩個線程正在使用Pulse並且等待交互,這可能導致死鎖。將其與AutoResetEvent類[...]的行爲進行對比「 –
進入/退出是相互排斥的,等待/脈衝(全部)用於等待和發信號。見http://en.wikipedia.org/wiki/Monitor_(synchronization) – dtb