我想知道在一个已经获得监视器的线程上调用Threa.Sleep是否会在进入睡眠状态之前解除锁定:
object o = new object();
Montior.Enter(o);
Thread.Sleep(1000);
Monitor.Exit(o);
当线程被挂起时 - 其他线程可以获取o
吗?
答案 0 :(得分:9)
不,线程在暂停/休眠之前不会释放lock
并且在睡眠线程唤醒并释放锁定的对象之前,没有其他线程能够获取o
答案 1 :(得分:7)
不,在Enter
和Exit
之间,没有其他线程可以在你中间执行任何操作。
答案 2 :(得分:5)
不,如果你睡觉,锁不会被释放。
如果想要发布,请使用Monitor.Wait(o, timeout)
;此外,您还可以使用此信号从另一个线程发出信号 - 另一个线程可以使用Monitor.Pulse[All]
(在持有锁定的情况下)比“超时”更早地唤醒等待线程(它将在此过程中重新获取锁定,太)。
请注意,无论何时使用Enter / Exit,您都应该考虑使用try / finally - 或者如果发生异常,您可能无法释放锁。
示例:
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); }
这会轻推当前在该对象上等待的任何线程(但如果没有对象醒来则什么都不做)。重点:等待线程仍然必须等待脉冲线程释放锁定,因为它需要重新获取。
答案 3 :(得分:3)
根据我的经验,在锁定块的中间调用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使锁定代码块保持同步。