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

时间:2012-02-26 15:49:27

标签: c# .net synchronization locking

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

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

当线程被挂起时 - 其他线程可以获取o吗?

4 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:7)

不,在EnterExit之间,没有其他线程可以在你中间执行任何操作。

答案 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使锁定代码块保持同步。