【问题标题】:Find deadlock in Task.WhenAll在 Task.WhenAll 中查找死锁
【发布时间】:2019-02-18 01:35:39
【问题描述】:

我发现下面的代码sn-p有死锁,虽然我已经通过读写锁解决了这个问题,但我仍然不知道Task.WhenAll中到底发生了什么导致死锁。

有问题的代码:

   public async static Task<Dictionary<string, Log4SerialPort>> AvailableLog4SerialPorts()
        {
            var ports = App.SerialPortService.GetAvailablePorts();
            await Task.WhenAll(ports.Select(async port =>
            {
                if (!_availableLog4SerialPorts.ContainsKey(port.Path))
                {
                    var log4Port = new Log4SerialPort(port);
                    var isValid = await log4Port.Verify();
                    if (isValid)
                    {
                        _availableLog4SerialPorts.Add(port.Path, log4Port);
                    }

                }
            }));
            return _availableLog4SerialPorts;
        }

通过添加读写锁,问题解决了:

   public async static Task<Dictionary<string, Log4SerialPort>> AvailableLog4SerialPorts()
        {
            var ports = App.SerialPortService.GetAvailablePorts();
            await Task.WhenAll(ports.Select(async port =>
            {
                rwl.AcquireReaderLock(VERIFY_TIMEOUT);
                if (!_availableLog4SerialPorts.ContainsKey(port.Path))
                {
                    rwl.ReleaseReaderLock();
                    var log4Port = new Log4SerialPort(port);
                    var isValid = await log4Port.Verify();
                    if (isValid)
                    {
                        rwl.AcquireWriterLock(VERIFY_TIMEOUT);
                        _availableLog4SerialPorts.Add(port.Path, log4Port);
                        rwl.ReleaseWriterLock();
                    }

                }
            }));
            return _availableLog4SerialPorts;
        }

_availableLog4SerialPorts 是一个静态字段。

log4Port.Verify() 不共享任何静态资源,它只是做一些耗时的任务。

似乎Task.WhenAll会自动锁定静态资源,但不确定它是如何工作的,以及这种情况下的详细阻塞原因。

【问题讨论】:

  • 如果结构不是线程安全的,那么在多线程环境中使用它们会产生意想不到的后果......如果不知道您正在使用的每个结构的工作原理,那么我们几乎不可能猜猜是什么导致了问题,但很高兴你解决了它。但请注意,Dictionary 不是线程安全的,谁知道Log4SerialPort 做了什么
  • 您可能必须从AvailableLog4SerialPorts 开始上链。你怎么称呼它?
  • 你说,我发现下面的代码sn-p有死锁。你怎么知道的?
  • @CodingYoshi @John @MichaelRandall Log4SerialPort 就像System.IO.Ports.SerialPort 的包装,而AvailableLog4SerialPorts 是静态Dictionary&lt;string, Log4SerialPort&gt;。我认为这是一个死锁,因为在我手动添加读写锁后,问题就解决了。而且我还在阅读其他已发布的问题,似乎是多线程中的字典

标签: c# multithreading xamarin task deadlock


【解决方案1】:

我做了一个小程序来重现这个问题,看起来程序被阻塞的原因就像@Michael Randall所说的那样,Dictionary在多线程环境中可能会导致意外行为。以下是测试截图。没有锁,程序将在执行过程中的任意点阻塞。

without locks

with locks(抱歉我还不能嵌入图片...)

感谢您的所有帮助:)

【讨论】:

  • 请将您的解决方案标记为已回答。帮助其他搜索问题以帮助他们,这样他们就不会浪费时间在已回答的问题上。谢谢!
  • @LeonLu-MSFT 会做的,系统还不允许我接受我自己的答案。
猜你喜欢
  • 1970-01-01
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-27
相关资源
最近更新 更多