我在想,如果一個電話就已經acquiered監視器將臨睡前釋放鎖的線程Threa.Sleep:調用了Thread.Sleep()鎖定語句中的.NET
object o = new object();
Montior.Enter(o);
Thread.Sleep(1000);
Monitor.Exit(o);
雖然該線程被暫停 - 可以通過其他線程獲取o
?
我在想,如果一個電話就已經acquiered監視器將臨睡前釋放鎖的線程Threa.Sleep:調用了Thread.Sleep()鎖定語句中的.NET
object o = new object();
Montior.Enter(o);
Thread.Sleep(1000);
Monitor.Exit(o);
雖然該線程被暫停 - 可以通過其他線程獲取o
?
沒有,如果你睡覺,鎖定不會被釋放。
如果你想想要發佈它,請使用Monitor.Wait(o, timeout)
;此外,還可以使用它從另一個線程發出信號 - 另一個線程可以使用Monitor.Pulse[All]
(同時持有鎖)在早於「超時」的時間內喚醒等待的線程(它也將重新獲取進程中的鎖)。
注意:只要使用進入/退出,你應該考慮使用try /終於過 - 或者,如果發生異常,你可能還沒解除鎖定。
例子:
bool haveLock = false;
try {
Monitor.Enter(ref haveLock);
// important: Wait releases, waits, and re-acquires the lock
bool wokeEarly = Monitor.Wait(o, timeout);
if(wokeEarly) {...}
} finally {
if(haveLock) Monitor.Exit(o);
}
另一個線程可以這樣做:
lock(o) { Monitor.PulseAll(o); }
將在該對象上等待當前輕推任意線程(但什麼都不做,如果沒有對象被喚醒)。強調:等待線程仍然需要等待脈衝線程釋放鎖,因爲它需要重新獲取。
但是Pulse方法會自動(和原子地...)釋放對象的鎖,right – 2012-02-27 06:40:45
@PiniSalim no,'Pluse'明確地做**不釋放鎖 - 另一個(等待)線程移動到* ready *隊列,並獲得鎖,並且只有當鎖由'Monitor.Exit'釋放時 - 也就是當它離開「另一個線程可以執行的」lock(o){...} 「例如。 – 2012-02-27 06:48:42
@PiniSalim或來自MSDN,重點mine:「接收到脈衝後,等待的線程移動到就緒隊列。當調用Pulse **的線程釋放鎖**時,就緒隊列中的下一個線程不一定是脈衝線)獲得鎖。「 – 2012-02-27 06:49:36
不,在Enter
和Exit
之間,沒有其他線程可以鎖定您在其間執行的任何操作。
沒有,該線程將不會暫停之前釋放lock
/睡眠
,並沒有其他的線程能夠獲得o
直到睡眠線程被喚醒和釋放鎖定的對象
從我的經驗,調用了Thread.Sleep在鎖塊的中間會導致鎖定線程失去鎖(即上下文切換)。 我跑下面的程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Thread t1 = new Thread(c1.DoSomthing);
Thread t2 = new Thread(c2.DoSomthing);
t1.Start();
Thread.Sleep(500);
t2.Start();
}
}
class Class1
{
object m_objSyncLock = new object();
ManualResetEvent m_objSleep = new ManualResetEvent(true);
public void DoSomthing()
{
Monitor.Enter(m_objSyncLock);
int i = 1; //break point here
Thread.Sleep(565);
i++; //break point here
Monitor.Exit(m_objSyncLock);
}
}
}
class Class2
{
object m_objSyncLock = new object();
public void DoSomthing()
{
lock (m_objSyncLock)
{
int i = 1; //break point here
i++;
}
}
}
添加斷點到線30,32,46,並注意行32發生第一,然後管線48,然後才線34 不這意味着Thread.Sleep調用使我失去了鎖定?
此外,使用ManualResetEvent.WaitOne代替Thread.sleep代碼時,正在執行的線程沒有失去排他性(除了開關ManualResetEvent的本身)。
我不是大師,但是這個簡單的測試表明Thread.Sleep可能會讓你在使用ManualResetEvent.WaitOne時保持鎖碼同步而失去鎖定。
我不能正確地找出你的觀點,因爲它很難找到行號。如果你可以在每一行中添加一條評論,你就可以說出調試器會發生什麼情況,這將有助於弄清楚你的觀點。 – 2017-08-10 09:58:05
我在代碼 – 2017-08-22 06:43:41
中添加了斷點位置啊現在我看到你錯了。您已創建了2個用於鎖定的對象。那不會做任何事情。 (如果你在2個地方有「新」,這意味着2個對象)。如果你想正確鎖定你應該鎖定在同一個對象上。 – 2017-08-23 08:44:13
是什麼讓你懷疑? – 2012-02-26 15:55:54
調用,鎖內的Thread.Sleep是無響應應用程序的祕訣。您應儘可能在鎖內執行最少量的工作,否則等待資源的其他線程將堆積等待獲取鎖。 – 2012-02-26 15:56:49
@JaredShaver除了在大量的情況下,例如鎖定將數據發送到從不同線程的負載獲取數據的硬件,但是如果發送數據太快會導致數據崩潰。 – 2015-07-24 09:15:18