Calling Thread.Sleep() inside lock statement in .net

杀马特。学长 韩版系。学妹 提交于 2020-01-03 16:55:08

问题


I was wondering if a call to Threa.Sleep on a thread that already acquiered a Monitor will release the lock before going to sleep:

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

While the thread is suspended - can other thread acquire o?


回答1:


No, the lock will not be released if you Sleep.

If you want to release it, use Monitor.Wait(o, timeout); further, you can also use this to signal from another thread - another thread can use Monitor.Pulse[All] (while holding the lock) to wake the waiting thread earlier than "timeout" (it will re-acquire the lock in the process, too).

Note that whenever using Enter/Exit, you should consider using try/finally too - or you risk not releasing the lock if an exception happens.

Example:

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

Another thread could do:

lock(o) { Monitor.PulseAll(o); }

Which will nudge any threads currently in a Wait on that object (but does nothing if no objects were waking). Emphasis: the waiting thread still has to wait for the pulsing thread to release the lock, since it needs to re-acquire.




回答2:


No, the thread won't release the lock before suspending/sleeping

and no other thread will be able to acquire o until the sleeping thread wakes up and releases the locked object




回答3:


No, between Enter and Exit, no other thread can take the lock whatever you do inbetween.




回答4:


From my experience, calling Thread.Sleep in the middle of a lock block would cause the locking thread to lose the lock (i.e context switch). I ran the following program:

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

Add break points to lines 30, 32, 46 and notice that line 32 occur 1st, then line 48, and only then line 34. Doesn't this mean that the Thread.Sleep call made me lose my lock?

Moreover, when using ManualResetEvent.WaitOne instead of Thread.Sleep, the executing thread didn't lose exclusivity (except the switch to ManualResetEvent itself).

I'm no guru but this simple test show that Thread.Sleep might make you lose the lock while using ManualResetEvent.WaitOne keeps the lock code block in sync.



来源:https://stackoverflow.com/questions/9454472/calling-thread-sleep-inside-lock-statement-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!