在 Task.WhenAll 中查找死锁
Find deadlock in Task.WhenAll
我发现下面的代码片段有死锁,虽然我已经通过使用读写锁解决了这个问题,但我仍然不知道 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会自动锁定静态资源,但不知道具体是如何工作的,具体的阻塞原因。
我做了一个小程序来重现这个问题,看起来程序被阻止的原因就像@Michael Randall 所说的那样,Dictionary
在多线程环境中可能会导致意外行为。以下是测试截图。如果没有锁,程序将在执行期间的任意点阻塞。
without locks
with locks(抱歉我还不能嵌入图片...)
感谢您的帮助:)
我发现下面的代码片段有死锁,虽然我已经通过使用读写锁解决了这个问题,但我仍然不知道 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会自动锁定静态资源,但不知道具体是如何工作的,具体的阻塞原因。
我做了一个小程序来重现这个问题,看起来程序被阻止的原因就像@Michael Randall 所说的那样,Dictionary
在多线程环境中可能会导致意外行为。以下是测试截图。如果没有锁,程序将在执行期间的任意点阻塞。
without locks
with locks(抱歉我还不能嵌入图片...)
感谢您的帮助:)