I think I am missing something obvious here:
Why does this code doesn't cause deadlock:
static void Main(string[] args)
{
object _lock1 = new object();
object _lock2 = new object();
Thread code1 = new Thread(() =>
{
lock (_lock1)
{
lock (_lock2)
{
Console.WriteLine("A");
Thread.Sleep(3000);
}
}
});
Thread code2 = new Thread(() =>
{
lock (_lock2)
{
lock (_lock1)
{
Console.WriteLine("B");
Thread.Sleep(3000);
}
}
});
code1.Start();
code2.Start();
code1.Join();
code2.Join();
Console.WriteLine("Done");
}
But this one does:
static void Main(string[] args)
{
object _lock1 = new object();
object _lock2 = new object();
Thread code1 = new Thread(() =>
{
lock (_lock1)
{
lock (_lock2)
{
Thread.Sleep(3000);
Console.WriteLine("A");
}
}
});
Thread code2 = new Thread(() =>
{
lock (_lock2)
{
Thread.Sleep(3000);
lock (_lock1)
{
Console.WriteLine("B");
}
}
});
code1.Start();
code2.Start();
code1.Join();
code2.Join();
Console.WriteLine("Done");
}
Both code snippets can cause deadlocks and should be avoided. It is just a coincidence, that first snippet didn't get into deadlock. Adding some operation between locks increases probability to get dead lock. For example, if you add Console.Writeline in between lock1 and lock2 it also increases probability of the deadlock. You can run your first snippet in loop and receive a deadlock. For example, this code get into deadlock after a while:
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
object _lock1 = new object();
object _lock2 = new object();
Thread code1 = new Thread(() =>
{
lock (_lock1)
{
lock (_lock2)
{
Console.WriteLine("A");
Thread.Sleep(100);
}
}
});
Thread code2 = new Thread(() =>
{
lock (_lock2)
{
lock (_lock1)
{
Console.WriteLine("B");
Thread.Sleep(100);
}
}
});
code1.Start();
code2.Start();
code1.Join();
code2.Join();
}
Console.WriteLine("Done");
}