Checking whether the current thread owns a lock

后端 未结 10 578
攒了一身酷
攒了一身酷 2021-02-02 13:32

Suppose I have the following code:

public class SomeClass()
{
    private readonly object _lock = new object();

    public void SomeMethodA()
    {
        lock         


        
相关标签:
10条回答
  • 2021-02-02 14:23

    Not the best thing to do but ...

    bool OwnsLock(object someLockObj)
    {
      if (Monitor.TryEnter(someLockObj))
      {
        Monitor.Exit();
        return false;
      }
      return true;
    }
    
    Debug.Assert(OwnsLock(_someLockObject), "_someLockObject should be locked when this method is called")
    
    0 讨论(0)
  • 2021-02-02 14:30

    But there does not appear to be such a method. Monitor.TryEnter does not help because locks are re-entrant. Therefore, if the current thread already owns the lock, TryEnter will still succeed and return true. The only time it will fail is if another thread owns the lock and the call times out.

    I found a workaround that works similar to Monitor.TryEnter() and yet doesn't have the re-entrant issues. Basically instead of using Monitor.TryEnter(), you can use Monitor.Pulse(). This function throws a SynchronizationLockException exception if the current thread doesn't hold the lock.

    example:

    try
    {
        System.Threading.Monitor.Pulse(lockObj);
    }
    catch (System.Threading.SynchronizationLockException /*ex*/)
    {
        // This lock is unlocked! run and hide ;)
    }
    

    Docs: http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx

    0 讨论(0)
  • 2021-02-02 14:31

    If you need this under .NET 4.5 see the accepted answer from @Dave .

    However, if you need this under .NET 3.5 or 4, you could replace the use of Monitor locks for a ReaderWriterLockSlim as follows.

    According to Joeseph Albahari this will approximately double your (uncontested) locking overhead, but it is still really fast (est. 40nS). (Disclaimer, that page does not state if the tests were done using a recursive lock policy.)

    public class SomeClass()
    {
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
    
    public void SomeMethodA()
    {
        _lock.EnterWriteLock();
        try
        {
            SomeHelperMethod();
    
            //do something that requires lock on _lock
        }
        finally
        {
           _lock.ExitWriteLock();
        }
    }
    
    private void SomeHelperMethod()
    {
        Debug.Assert(_lock.IsWriteLockHeld);
    
        //do something that requires lock on _lock
    }
    }
    

    If you feel that is too non-performant you can of course write your own wrapper class around Monitor locks. However, other posts have mentioned a boolean flag which is misleading as the question is not "Is the lock held by any thread?" (which is a foolish and dangerous question to ask). The correct question is "Is the lock held by THIS thread?". No problem though, just make the 'flag' a ThreadLocal counter(for recursive lock support) and ensure updates are done after Monitor.Enter and before Monitor.Exit. As an improvement assert that the counter does not drop below 0 on "unlock" as that would indicate unbalanced Enter/Exit calls.

    Another reason for the wrapper would be to avoid having someone slip in _lock.EnterReadLock calls. Depending on the usage of the class those might actually be helpful, but a surprising number of coders do not understand Reader-Writer Locks.

    0 讨论(0)
  • 2021-02-02 14:33

    This is supported in .NET 4.5 using Monitor.IsEntered(object).

    0 讨论(0)
提交回复
热议问题