我发现下面的代码段具有死锁,尽管我已经通过使用读写锁解决了这个问题,但我仍然不知道Task.WhenAll到底会导致死锁的确切情况是什么。
问题代码:
%*d
通过添加读写锁,问题得以解决:
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
不共享任何静态资源,它仅执行一些耗时的任务。
似乎Task.WhenAll会自动锁定静态资源,但不确定这种情况下的工作方式以及详细的阻止原因。
答案 0 :(得分:1)
我制作了一个小程序来重现此问题,该程序被阻止的原因似乎是@Michael Randall所说的,Dictionary
在多线程环境中可能会导致意外的行为。以下是测试的屏幕截图。没有锁,程序将在执行过程中的任意位置阻塞。
with locks(对不起,我仍然无法嵌入图片...)
感谢您的所有帮助:)