任务取消异常(ThrowForNonSuccess)

时间:2014-01-17 16:11:22

标签: c# .net asynchronous task-parallel-library async-await

这是这个问题的延续: Multiple Task Continuation

我在答案中更改了我的代码,但是当我尝试运行任务时,我现在收到了TaskCancelledExceptions

public virtual async Task RunAsync(TaskWithProgress task)
{
    Show();
    TaskIsRunning();
    await SetCompletedHandler(TaskComplete());
    await SetCancelledHandler(TaskCancelled())
    await SetFaultedHandler(TaskFaulted());
    await task;
    Close();
}

但是以下代码没有。我有点卡住原因。

public virtual Task RunAsync(TaskWithProgress task)
{
    Show();
    TaskIsRunning();
    SetCompletedHandler(TaskComplete());
    SetCancelledHandler(TaskCancelled())
    SetFaultedHandler(TaskFaulted());
    return task;
}

调用代码基本上涉及以下内容:

await progressDialog.RunAsync(task);

编辑:

我不会在任何地方取消cancellationtoken,所以我不明白为什么会抛出这个例外。

三个SetXXXHandler()方法基本上执行以下具有不同延续状态的代码:

task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);

堆栈跟踪在这里:

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FugroDXExt.frmBaseProgressAsync.<RunAsync>d__7.MoveNext() in d:\C#\FugroDXExt\trunk\frmBaseProgressAsync.cs:line 92
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FCP.Forms.frmProcessing.<mnuApplyCenteredSmoothing_ItemClick>d__34.MoveNext() in d:\C#\FCP\FCP\Forms\frmProcessing.cs:line 578

Close()只需关闭表单即可。如果我删除该行,则会发生同样的事情。

1 个答案:

答案 0 :(得分:9)

你说SetCancelledHandler只是为任务增加了一个延续。我假设同样的任务RunAsync作为参数得到,虽然我无法通过你的代码告诉我SetCancelledHandler如何继续执行任务(我假设我们缺少一些代码)。反正...

您在任务完成,取消并出现故障时将运行的任务上注册3个续集。现在让我们假设原始任务成功完成而没有被取消。这意味着你的两个延续(OnCanceledOnFaulted)将无法运行,因为它们不需要。告诉任务不在TPL中运行的方法是取消它,这会自动发生。

您的2个代码段之间的区别在于,在第一个代码片段中await任务延续,并且它们会被取消,从而解释您的异常。在第二个片段中,您不等待延续,只是成功运行完成的原始任务。

P.S:我认为第二种选择更合适。您不需要await所有这些延续。如果需要,你想让它们运行。

TL; DR:你await取消了继续任务。继续任务,而不是原始任务,是抛出异常的任务。