132

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 
        }
    }       
 }
Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
Guy
  • 65,082
  • 97
  • 254
  • 325
  • 7
    Might we consider changing the title of this question - perhaps to something like the recently-closed [Why do nested locks not cause a deadlock?](http://stackoverflow.com/questions/5035126/why-do-nested-locks-not-cause-a-deadlock) As it stands, the title seems almost designed to prevent people from discovering it. – Jeff Sternal Feb 17 '11 at 21:59
  • 13
    Actually I found this based on the search word 'reentrant', and it answered my question. If it's a dup question, that's a different issue... – emfurry Oct 05 '11 at 16:17
  • I agree with @JeffSternal comment this question assumes the person searching for the question is already familiar with "Re-entrant" locks. Another duplication question I think had a good title for this: http://stackoverflow.com/questions/3687505/recursive-nested-locking-in-c-sharp-with-the-lock-statement – Luis Perez Jun 16 '14 at 16:03

4 Answers4

167

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.)

Community
  • 1
  • 1
Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • 1
    Especially in different sequences. – Marc Gravell Dec 24 '08 at 17:45
  • 6
    Re recursion; indeed; for Guy's benefit, the term is re-entrant – Marc Gravell Dec 24 '08 at 17:48
  • Thanks for the clarification on the terminology - I've edited and corrected the question. – Guy Dec 24 '08 at 18:43
  • This question seems to get quite a bit of attention so I've updated my answer with a couple of other notes that I've come up with since I first wrote it. – Neil Barnwell Apr 20 '11 at 11:33
  • 1
    Actually, I don't think the order in which you release locks matters. The order in which you choose them definitely does, but as long as releasing the lock isn't conditional upon anything (you can release at any time), you should be fine as long as you release all the locks that you have acquired. – bobroxsox Jun 12 '14 at 23:20
  • @bobroxsox Yes, provided you're just releasing and not performing _anything_ additional, like acquiring another lock. – AyCe Apr 27 '23 at 23:12
22

Well, Monitor allows re-entrancy, so you can't deadlock yourself... so no: it shouldn't do

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
8

If a thread is already holding a lock, then it will not block itself. The .Net framework ensures this. You only have to make sure that two threads do not attempt to aquire the same two locks out of sequence by whatever code paths.

The same thread can aquire the same lock multiple times, but you have to make sure you release the lock the same number of times that you aquire it. Of course, as long as you are using the "lock" keyword to accomplish this, it happens automatically.

Jeffrey L Whitledge
  • 58,241
  • 9
  • 71
  • 99
  • Note that that's true for monitors, but not necessarily other kinds of lock. – Jon Skeet Dec 24 '08 at 19:31
  • (Not wishing to imply that you didn't know that, of course - just that it's an important distinction :) – Jon Skeet Dec 24 '08 at 19:34
  • That's a good point. I was actually going to change "lock" to "monitor" throughout, but then I got distracted. And lazy. And the behavior is also true for Windows mutex kernal objects, so I figured, close enough! – Jeffrey L Whitledge Dec 25 '08 at 01:49
5

No, this code will not have dead locks. If you really want to create deadlock simplest one requires at-least 2 resources. Consider dog and the bone scenario.

  1. A dog has full control over 1 bone so any other dog has to wait.
  2. 2 dog with 2 bones are minimum required to create a deadlock when they lock their bones respectively and seek others bone too.

.. so on and so forth n dogs and m bones and cause more sophisticated deadlocks.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Rishabh Jain
  • 518
  • 6
  • 11