Search code examples
c#lockingnotify

In C#, can object being locked/unlocked be notified?


The question is, can I create a class that gets notified when it is locked and unlocked.

object myLockObj = new SpecialLockNotifyClass("Bob");
lock (myLockObj)
{
   Console.WriteLine("Hello");
}

And the output you would get is:

Trying to lock Bob.
Bob is locked.
Hello.
Bob is unlocked.

The idea is two-fold:

1) Set it up so one can see when something is trying to lock (by seeing "trying" message" and waiting indefinitely (by not seeing "locked" message) everywhere the lock is used

2) Turn off the outputs and switch back to standard locking when one believes the deadlock problems are solved.


Solution

  • lock is just syntactic sugar for Monitor.Enter/Monitor.Exit.

    You could wrap the Monitor access in a custom Disposable type, and replace your lock block with a using block. EG

        sealed class MyLock : IDisposable
        {
            private object syncRoot;
            bool lockWasTaken = false;
    
            public MyLock(object syncRoot)
            {
                this.syncRoot = syncRoot;
                BeforeLock();
                Monitor.Enter(syncRoot, ref lockWasTaken);
            }
            public void Exit()
            {
                if (lockWasTaken)
                {
                    Monitor.Exit(syncRoot);
                    lockWasTaken = false;
                    AfterUnlock();
                }
            }
    
            void BeforeLock()
            {
                //...
            }
    
            void AfterUnlock()
            {
                //...
            }
    
            void IDisposable.Dispose()
            {
                Exit();
            }
        }
    

    You could even wrap that in an Extension method and write:

    using (foo.Lock())
    {
    }
    

    Or if you just want to track the attempts at locking the object you could replace

    lock(foo) { . . .}
    

    with

    lock(TrackLock(foo))  { . . .}
    

    where

    public static object TrackLock(object o)
    {
        Console.WriteLine($"Locking {o.ToString()}");
        return o;
    }