Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do nested locks not cause a deadlock?

Why does this code not cause a deadlock?

   private static readonly object a = new object();

...

   lock(a)
   {
      lock(a)
      {
         ....
      }
   }
like image 518
Myster Avatar asked Feb 17 '11 21:02

Myster


People also ask

What is a nested lock?

Nested Locking. A thread can repeatedly lock the same object, either via multiple calls to Monitor.Enter, or via nested lock statements. The object is then unlocked when a corresponding number of Monitor.Exit statements have executed, or the outermost lock statement has exited.

Can deadlock occur with single lock?

Yes, you lock the mutex or critical section but forget to unlock it (say in a certain exit code path). The next thread that tries to access this code is a deadlock.


3 Answers

If a thread already holds a lock, then it can "take that lock" again without issue.


As to why that is, (and why it's a good idea), consider the following situation, where we have a defined lock ordering elsewhere in the program of a -> b:

void f()
{
    lock(a)
    { /* do stuff inside a */ }
}

void doStuff()
{
    lock(b)
    {
        //do stuff inside b, that involves leaving b in an inconsistent state
        f();
        //do more stuff inside b so that its consistent again
    }
}

Whoops, we just violated our lock ordering and have a potential deadlock on our hands.

We really need to be able to do the following:

function doStuff()
{
    lock(a)
    lock(b)
    {
        //do stuff inside b, that involves leaving b in an inconsistent state
        f();
        //do more stuff inside b so that its consistent again
    }
}

So that our lock ordering is maintained, without self-deadlocking when we call f().

like image 179
Anon. Avatar answered Sep 30 '22 17:09

Anon.


The lock keyword uses a re-entrant lock, meaning the current thread already has the lock so it doesn't try to reacquire it.

A deadlock occurs if

Thread 1 acquires lock A
Thread 2 acquires lock B
Thread 1 tries to acquire lock B (waits for Thread 2 to be done with it) Thread 2 tries to acquire lock A (waits for Thread 1 to be done with it)

Both threads are now waiting on each other and thus deadlocked.

like image 38
Davy8 Avatar answered Sep 30 '22 19:09

Davy8


From section 8.12 of the C# language specification:

While a mutual-exclusion lock is held, code executing in the same execution thread can also obtain and release the lock. However, code executing in other threads is blocked from obtaining the lock until the lock is released.

It should be obvious that the internal lock scope is in the same thread as the outer.

like image 25
Dan J Avatar answered Sep 30 '22 17:09

Dan J