【问题标题】:How to handle task cancellation using ContinueWith?如何使用 ContinueWith 处理任务取消?
【发布时间】:2017-09-05 12:28:31
【问题描述】:

我有以下示例:

public void Run()
{
    var ctc = new CancellationTokenSource();

    try
    {
        DoAsync(ctc).Wait();

        Console.WriteLine("Done");
    }
    catch (AggregateException exception)
    {
        Console.WriteLine("Inside try-catch block");
        Console.WriteLine();
        Console.WriteLine(exception);

        exception.Handle(ex =>
        {
            Console.WriteLine(ex.Message);
            return true;
        });
    }
}

private async Task DoAsync(CancellationTokenSource ctc)
{
    Console.WriteLine("DoAsync started");

    await Task.Run(() =>
                Console.WriteLine("DoAsync Run"),
                ctc.Token
            )
            .ContinueWith(antecedent =>
                Console.WriteLine("DoAsync Run cancelled"),
                TaskContinuationOptions.OnlyOnCanceled
            );

    Console.WriteLine("DoAsync finished");
}

我创建了一个方法 (DoAsync),它执行一些异步工作并且可以随时取消。

如您所见,Task.Run 获得了一个取消令牌。出于这个原因,我使用 continuationOptions = TaskContinuationOptions.OnlyOnCanceled 创建了延续任务。

因此,我希望仅在请求取消时调用延续任务,而在其他情况下 - 被忽略。

但在我的实现任务中,由 ContinueWith 返回的任务在其前面的任务未被取消时会引发异常:

DoAsync started
DoAsync Run

Inside try-catch block
System.AggregateException...

A task was canceled.

我可以通过添加另一个 ContinueWith 来解决此问题,如下例所示:

await Task.Run(() =>
        Console.WriteLine("DoAsync Run"),
        ctc.Token
    )
    .ContinueWith(antecedent =>
        Console.WriteLine("DoAsync Run cancelled"),
        TaskContinuationOptions.OnlyOnCanceled
    )
    .ContinueWith(antecedent => { });

而且这段代码不会抛出任何异常。

但是我可以使用单个 ContinueWith 正确处理取消吗?

【问题讨论】:

  • 你试过只传token,不传token源吗?
  • @Fildor,我同意我应该传递令牌而不是令牌源。但它是如何解决我的问题的呢?
  • 它可能不会。这就是为什么它只是一个评论。但也许它会减少副作用。我看不出你的代码不能按预期工作的明显原因......(还)
  • 您是否有理由组合 async/await 并继续?您可以在 await 周围使用 try/catch 重新创建它并捕获 catch (OperationCanceledException ex) when ex.CancellationToken.Equals(ctc.Token) { Console.WriteLine("DoAsync Run cancelled"); }
  • @VladyslavYefremov:你根本不应该使用ContinueWith。将awaittry/catch 一起使用会产生更易于维护的代码。

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


【解决方案1】:

ContinueWith的备注具体说明:

如果通过continuationOptions参数指定的延续条件不满足,延续任务将被取消而不是计划。

由于未满足您为先行词指定的条件(即未取消),因此将继续设置为取消。您等待取消的任务,因此导致DoAsync 出现操作取消异常。

【讨论】:

    猜你喜欢
    • 2019-07-15
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    • 2013-09-21
    相关资源
    最近更新 更多