如果我在Thread.Sleep(0)方法中注释或传递0,那么就没有死锁.在其他情况下,存在僵局.uptask由线程轮询中的线程执行,这需要一些时间.同时,主线程获取lockB,lockA并打印字符串并释放锁.之后uptask开始运行,它看到lockA和lockB是免费的.所以在这种情况下没有死锁.但是如果我在平均时间内uptask进入主线程并且看到lockB被锁定并且发生了死锁.任何人都可以更好地解释或验证这是否是原因?
class MyAppClass
{
public static void Main()
{
object lockA = new object();
object lockB = new object();
var uptask = Task.Run(() =>
{
lock (lockA)
{
lock (lockB)
{
Console.WriteLine("A outer and B inner");
}
}
});
lock (lockB)
{
//Uncomment the following statement or sleep with 0 ms and see that there is no deadlock.
//But sleep with 1 or more lead to deadlock. Reason?
Thread.Sleep(1);
lock (lockA)
{
Console.WriteLine("B outer and A inner");
}
}
uptask.Wait();
Console.ReadKey();
}
}
Run Code Online (Sandbox Code Playgroud)
你真的不能依靠Thread.Sleep防止僵局.它在您的环境中工作了一段时间.它可能无法一直工作,可能无法在其他环境中工作.
由于您以相反的顺序获取锁,因此存在死锁的可能性.
要防止死锁,请确保按顺序获取锁(例如,锁定A然后在两个线程中使用lockB).
我最好的猜测是,如果你没有睡觉,那么主线程将在另一个线程(来自线程池)获得lockA之前获取并释放两个锁.请注意,在线程池上安排和运行Task需要一些时间.在大多数情况下,它是可以忽略的.但就你的情况而言,它有所作为.
要验证这一点,请在之前添加以下行uptask.Wait():
Console.WriteLine("main thread is done");
Run Code Online (Sandbox Code Playgroud)
从线程池线程获取lockA之后的这一行:
Console.WriteLine("Thread pool thread: obtained lockA");
Run Code Online (Sandbox Code Playgroud)
如果没有死锁,您将在线程池线程将其消息打印到控制台之前看到第一条消息打印到控制台.