2013-06-05 93 views
3

我仍然不確定這兩個調用之間的差異。從MSDN開始,Monitor.Enter vs Monitor.Wait

Monitor.Enter(Object)獲取對指定對象的排他鎖。

Monitor.Wait(Object)釋放對象的鎖定並阻塞當前線程,直到它重新獲取鎖定。

從這我假設Monitor.Wait是一樣的Monitor.Enter,除了它釋放對象的鎖定之前重新獲取。

當前線程是否必須首先鎖定鎖定?一個不同的線程如何強制釋放一個對象的鎖?爲什麼同一個線程想要重新獲取鎖?

+2

進入/退出是相互排斥的,等待/脈衝(全部)用於等待和發信號。見http://en.wikipedia.org/wiki/Monitor_(synchronization) – dtb

回答

4

根據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? 
} 
1

考慮這個例子:

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)

現在讓我們看一個更復雜的例子,其中WaitPulse發揮作用。

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,你可以確保有。

+0

從其他預期的答案「只有當你已經擁有鎖定時,你才能調用Monitor.Wait(Object)」。當生產者有鎖時,消費者可以調用Monitor.Wait(隊列)嗎? –

+0

製作者在短時間內鎖定了一個'Queue.Enqueue'和一個'Monitor.Pulse'調用所需的時間,後者放棄了鎖定。消費者要麼完全在鎖區之外,這意味着他只需要獲得鎖,稱爲「等待」,由於持續的「脈衝」而立即停止等待,或者他在「等待」呼叫中,使他重新獲得鎖定並且做他的消耗的東西。 –

+0

根據[Monitor.Pulse()](http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx)上的文檔,看起來像是一個等待發生的死鎖:「 Monitor類沒有保持狀態,指示已經調用了Pulse方法,因此,如果在沒有線程正在等待時調用Pulse,則下一個調用Wait塊的線程就像Pulse從未被調用一樣,如果兩個線程正在使用Pulse並且等待交互,這可能導致死鎖。將其與AutoResetEvent類[...]的行爲進行對比「 –

相關問題