在.net中的lock语句中调用Thread.Sleep()

我想知道在一个已经获得监视器的线程上调用Threa.Sleep是否会在进入睡眠状态之前释放锁定:

object o = new object(); Montior.Enter(o); Thread.Sleep(1000); Monitor.Exit(o); 

线程被挂起 – 其他线程可以获得吗?

不,如果你睡觉,锁将不会被释放。

如果释放它,请使用Monitor.Wait(o, timeout) ; 此外,您还可以使用此信号从另一个线程发出信号 – 另一个线程可以使用Monitor.Pulse[All] (同时持有锁定)以比“timeout”更早地唤醒等待线程(它将在此过程中重新获取锁定,也)。

请注意,每当使用Enter / Exit时,您都应该考虑使用try / finally – 或者如果发生exception,您可能无法释放锁。

例:

 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); } 

这将推动当前在该对象上等待的任何线程(但如果没有对象醒来则什么都不做)。 重点:等待线程仍然必须等待脉冲线程释放锁定,因为它需要重新获取。

不,线程在暂停/hibernate之前不会释放lock

并且在睡眠线程唤醒并释放锁定的对象之前,没有其他线程能够获取o

不,在EnterExit之间,没有其他线程可以在你之间做任何事情。

根据我的经验,在锁定块的中间调用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行出现在第1行,然后是第48行,然后是第34行。这是不是意味着Thread.Sleep调用让我失去锁定?

此外,当使用ManualResetEvent.WaitOne而不是Thread.Sleep时,执行线程不会失去排他性(除了切换到ManualResetEvent本身)。

我不是大师,但是这个简单的测试显示Thread.Sleep可能会让你在使用ManualResetEvent时失去锁定.WaitOne使锁定代码块保持同步。