在.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

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

否,线程在挂起/休眠之前不会释放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); }

它将轻推当前在该对象上等待的任何线程(但如果没有对象唤醒,则不执行任何操作)。强调:等待线程仍然必须等待脉冲线程释放锁,因为它需要重新获取。

否,在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时,执行线程没有失去独占性(除了切换到ManualResetAvent本身)。

我不是大师,但这个简单的测试表明,Thread.Sleep可能会让你在使用ManualResetEvent.WaitOne时丢失锁。