Why do nested locks not cause a deadlock?
C#asp.netDeadlockC# Problem Overview
Why does this code not cause a deadlock?
private static readonly object a = new object();
...
lock(a)
{
lock(a)
{
....
}
}
C# Solutions
Solution 1 - C#
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()
.
Solution 2 - C#
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.
Solution 3 - C#
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.