Почему Task.whehenall не может завершить, когда все его входные задачи выполнены, если задействованы блокировкиC#

Место общения программистов C#
Ответить
Anonymous
 Почему Task.whehenall не может завершить, когда все его входные задачи выполнены, если задействованы блокировки

Сообщение Anonymous »

См. Ниже для полного минимального резо (консольный проект Net9).
Когда он тупик, и я прикрепляю отладчик, я вижу, что единственная входная задача к whenalltas Строка 50, пытаясь ввести блокировку.
Обратите внимание, что строка 50 ожидает входа в блокировку, была запущена как явно отдельная задача с помощью задачи.run, и, следовательно, не часть BatchProcessingTask , эта поток A в строке 33 ждет. Ожидается.using System.Diagnostics;

while (true)
{
var testTask = Test();
var time = Stopwatch.GetTimestamp();
await Task.WhenAny(testTask, Task.Delay(TimeSpan.FromSeconds(3)));
Console.WriteLine($"Test {Stopwatch.GetElapsedTime(time)}");
if (testTask.IsCompleted is false)
{
Debugger.Launch();
// only here so it won't start next iteration while the debugger attaches and breaks
await Task.Delay(TimeSpan.FromSeconds(60));
}
}

async Task Test()
{
var applicationStoppingCts = new CancellationTokenSource();
var batchProcessingTask = Task.CompletedTask;
var batchLock = new Lock();
applicationStoppingCts.Token.Register(() =>
{
lock (batchLock)
{
// this works as expected, nice and deadlock free
//batchProcessingTask.Wait();

// this deadlocks
// debugging we you can observe that batchProcessingTask.IsCompleted is true,
// but whenAllTask.IsCompleted is false, holding the lock hostage forever
var whenAllTask = Task.WhenAll([batchProcessingTask]);
whenAllTask.Wait();
}
});

batchProcessingTask = ProcessBatch();
await Task.Delay(TimeSpan.FromSeconds(1));
await applicationStoppingCts.CancelAsync();
return;

Task ProcessBatch()
{
var batchTask = Task.Delay(TimeSpan.FromSeconds(2));

Task.Run(async () =>
{
// omitted actual logic for checking new batch etc.
await batchProcessingTask;
lock (batchLock)
{
if(applicationStoppingCts.Token.IsCancellationRequested)
return;
batchProcessingTask = ProcessBatch();
}
});
return batchTask;
}
}


Подробнее здесь: https://stackoverflow.com/questions/796 ... mpleted-if
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»