c# - 使用 Thread.Sleep 解决锁定死锁

标签 c# multithreading

如果我在 Thread.Sleep(0) 方法中注释或传递 0,则不会出现死锁。在其他情况下会出现死锁。 uptask 由线程轮询中的线程执行,这需要一些时间。同时,主线程获取 lockB、lockA 并打印字符串并释放锁。之后 uptask 开始运行,它发现 lockA 和 lockB 是空闲的。所以在这种情况下不存在死锁。但是如果我同时 sleep 主线程 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();
    }
}

最佳答案

您真的不能依赖 Thread.Sleep 来防止死锁。它在您的环境中工作了一段时间。它可能不会一直工作,也可能不会在其他环境中工作。

由于您是以相反的顺序获取锁,因此存在死锁的可能性。

为防止死锁,请确保按顺序获取锁(例如,在两个线程中先是 lockA,然后是 lockB)。

我对发生这种情况的最佳猜测是,如果您不休眠,那么主线程将在另一个线程(来自线程池)获得 lockA 之前获得并释放这两个锁。请注意,在线程池上调度和运行任务需要一些时间。在大多数情况下,它是可以忽略的。但对于您的情况,它有所作为。

要验证这一点,请在 uptask.Wait() 之前添加以下行:

Console.WriteLine("main thread is done");

从线程池线程获取 lockA 后的这一行:

Console.WriteLine("Thread pool thread: obtained lockA");

在没有死锁的情况下,在线程池线程将其消息打印到控制台之前,您将看到第一条消息打印到控制台。

关于c# - 使用 Thread.Sleep 解决锁定死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33302906/

相关文章:

C# 谷歌登录

c++ - 使用哪个容器和锁定机制?

python - 了解 Pool 中已完成多少任务

java - 如何让几十个线程同时运行

c# - Selenium 多次点击链接

c# - AutoMapper Custom Resolver 在构造函数中请求可选参数

c# - WPF 可检查菜单项中缺少复选标记

c# - 合并 2 个整数的文本而不是将它们加在一起

java - 如何停止/启动或重新启动计时器线程

c# - 使用字符串类型的参数进行线程化