Найти тупик в Task.WhenAll - PullRequest
       26

Найти тупик в Task.WhenAll

0 голосов
/ 18 февраля 2019

Я обнаружил, что приведенный ниже фрагмент кода имеет тупиковую ситуацию, хотя я уже решил эту проблему с помощью блокировки чтения и записи, но до сих пор не представляю, что именно происходит под защитой в Task.When, что вызывает тупик.

Проблематичнокод:

   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 автоматически заблокирует статические ресурсы, но не уверен, как это работает, и подробные причины блокировки в этом случае.

1 Ответ

0 голосов
/ 18 февраля 2019

Я создал небольшую программу для воспроизведения этой проблемы, и, похоже, причина, по которой программа заблокирована, заключается в том, как сказал @Michael Randall: Dictionary в многопоточной среде может вызвать непреднамеренное поведение.Ниже приведены скриншоты теста.Без блокировок программа будет блокироваться в любой произвольной точке во время выполнения.

без блокировок

с блокировками (К сожалению, я все еще не могу вставлять изображения...)

Спасибо за помощь:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...