Re-entrant locks in C#

Guy picture Guy · Dec 24, 2008 · Viewed 28.3k times · Source

Will the following code result in a deadlock using C# on .NET?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

Answer

Neil Barnwell picture Neil Barnwell · Dec 24, 2008

No, not as long as you are locking on the same object. The recursive code effectively already has the lock and so can continue unhindered.

lock(object) {...} is shorthand for using the Monitor class. As Marc points out, Monitor allows re-entrancy, so repeated attempts to lock on an object on which the current thread already has a lock will work just fine.

If you start locking on different objects, that's when you have to be careful. Pay particular attention to:

  • Always acquire locks on a given number of objects in the same sequence.
  • Always release locks in the reverse sequence to how you acquire them.

If you break either of these rules you're pretty much guaranteed to get deadlock issues at some point.

Here is one good webpage describing thread synchronisation in .NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Also, lock on as few objects at a time as possible. Consider applying coarse-grained locks where possible. The idea being that if you can write your code such that there is an object graph and you can acquire locks on the root of that object graph, then do so. This means you have one lock on that root object and therefore don't have to worry so much about the sequence in which you acquire/release locks.

(One further note, your example isn't technically recursive. For it to be recursive, Bar() would have to call itself, typically as part of an iteration.)