在.net中的lock语句中调用Thread.Sleep()
本文关键字:Thread Sleep 调用 net 中的 lock 语句 | 更新日期: 2023-09-27 18:25:55
我想知道对thread.Sleep的调用是否会在进入睡眠之前释放锁:
object o = new object();
Montior.Enter(o);
Thread.Sleep(1000);
Monitor.Exit(o);
当线程挂起时,其他线程是否可以获取o
?
否,线程在挂起/休眠之前不会释放lock
并且没有其他线程能够获取CCD_ 3,直到休眠线程唤醒并释放锁定对象
否,如果您处于睡眠状态,则不会释放锁。
如果希望释放它,请使用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); }
它将轻推当前在该对象上等待的任何线程(但如果没有对象唤醒,则不执行任何操作)。强调:等待线程仍然必须等待脉冲线程释放锁,因为它需要重新获取。
否,在Enter
和Exit
之间,无论您在两者之间做什么,都没有其他线程可以获取锁。
根据我的经验,调用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时,执行线程没有失去独占性(除了切换到ManualResetAvent本身)。
我不是大师,但这个简单的测试表明,Thread.Sleep可能会让你在使用ManualResetEvent.WaitOne时丢失锁。