等待任务永远不会完成,即使它的状态转换为' RanToCompletion'

时间:2015-10-28 10:51:54

标签: c# async-await taskcompletionsource

首先,道歉 - 我无法在适当简单的示例应用程序中重现此行为。在重构调用代码之前,此功能正在运行。

我试图使用TaskCompletionSource来表示异步操作的结束(长时间运行的进程完成,或者超时可能会使用TrySetResult()发出完成信号)。

我的问题是,尽管我可以看到任务正在从" WaitingForActivation"到" RanToCompletion",对等待的调用永远不会完成。

作为测试,我创建了一个Task Continuation,这个被调用,我添加了一个Timer来显示任务状态:

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 个答案:

答案 0 :(得分:2)

我很确定调用代码的某些位置的调用代码阻塞了一个任务,并且该代码在同步上下文中执行(即,在UI线程上或从ASP.NET请求中执行) 。这将cause a deadlock我将在我的博客中全面解释。最正确的解决方案是使用Wait替换阻止(通常是Resultawait来电)。

ContinueWith未被阻止的原因是因为它使用当前TaskScheduler而不是当前SynchronizationContext,所以在这种情况下它可能最终会在线程池上运行。如果我对调用代码阻止的猜测是正确的,那么如果您将ContinueWith传递给TaskScheduler.FromCurrentSynchronizationContext()$autoload_function也会死锁。