Ожидание задачи никогда не завершается, хотя ее состояние переходит в RanToCompletion

Во-первых, извинения - я не могу воспроизвести это поведение в достаточно простом примере приложения. Эта функциональность работала до некоторого рефакторинга вызывающего кода.

Я пытаюсь использовать TaskCompletionSource для оповещения об окончании асинхронной операции (либо длительный процесс завершается, либо тайм-аут может сигнализировать о завершении с помощью TrySetResult()).

Моя проблема в том, что, хотя я вижу, что Задача переходит из "WaitingForActivation" в "RanToCompletion", вызов await никогда не завершается.

В качестве теста я создал продолжение задачи, и это называется IS, и я добавил таймер для отображения состояний задачи:

async Task<Foo> WaitForResultOrTimeoutAsync()
{
        //... [Create 'pendingReq' with its TaskCompletion property]

        TaskCompletionSource<Foo> myCompletion = pendingReq.TaskCompletion;

        Task<Foo> theTask = myCompletion.Task;

        var taskContinuation = theTask.ContinueWith(resp =>
        {
            Console.WriteLine("The task completed");
            return resp.Result;
        });

        new Timer(state =>
        {
            Console.WriteLine("theTask TaskCompletion state is {0}", theTask.Status);
            Console.WriteLine("taskContinuation TaskCompletion state is {0}", taskContinuation.Status);
        }, null, 0, 1000);

        //var result = await theTask;
        var result = await taskContinuation;
        Console.WriteLine("We're FINISHED");    // NEVER GETS HERE
        return result;
}

Это приводит к следующему выводу:

theTask TaskCompletion state is WaitingForActivation
taskContinuation TaskCompletion state is WaitingForActivation
theTask TaskCompletion state is WaitingForActivation
taskContinuation TaskCompletion state is WaitingForActivation
The task completed
theTask TaskCompletion state is RanToCompletion
taskContinuation TaskCompletion state is RanToCompletion
theTask TaskCompletion state is RanToCompletion
taskContinuation TaskCompletion state is RanToCompletion

Конечно, с продолжением удара, непосредственно ожидающее Задачу также должно завершиться, нет? Какие внешние (вызывающие) факторы могут быть для такого поведения?

1 ответ

Решение

Я уверен, что вызывающий код в какой-то момент вверх по стеку вызовов блокирует задачу, и что этот код выполняется в контексте синхронизации (т. Е. В потоке пользовательского интерфейса или из запроса ASP.NET). Это приведет к тупику, который я полностью объясню в своем блоге. Наиболее правильным решением является замена блокировки (обычно Wait или же Result вызов) с await,

Причина ContinueWith не заблокирован, потому что он использует текущий TaskScheduler вместо текущего SynchronizationContextтак что в этом случае он, вероятно, будет работать в пуле потоков. Если мои предположения о блокировке вызывающего кода верны, то ContinueWith будет также тупик, если вы передадите его TaskScheduler.FromCurrentSynchronizationContext(),

Другие вопросы по тегам