CancellationToken未能取消所有任务

3

我是一个对.NET中TPL不熟悉的新手。我想了解令牌(CancellationToken)以及如何使用它来取消执行的任务。下面的代码只传输了一个被取消的任务,而同样的令牌被传递给了两个任务。我的假设是,如果第一个任务超时并且执行了 ctx.Cancel(),那么为什么我只看到一个异常,而不是两个任务都被取消了?我错过了什么,如何确保两个任务都被取消并且不会占用内存资源。

    static void Main(string[] args)
    {
        Console.WriteLine("Starting application");
        var ctx = new CancellationTokenSource();
        var token = ctx.Token;
        try
        {
            var task1 = new Program().Run("task1", token);
            var task2 = new Program().Run("task2", token);

            if (!task1.Wait(1000)) 
                ctx.Cancel();

            task2.Wait();
        }
        catch (AggregateException ex)
        {
            Console.WriteLine("Aggregate Exception occurred");
            foreach (var e in ex.InnerExceptions)
            {
                Console.WriteLine(e.Message);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine($"Main Exception: {e.Message}");
        }
        finally
        {
            Console.WriteLine("Finish Application");
            ctx.Dispose();
        }
    }

    private async Task Run(string name, CancellationToken token)
    {
        while(true)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Task Cancelled");
                token.ThrowIfCancellationRequested();
            }
            Console.WriteLine($"Executing {name} ...");
            await Task.Delay(250, token);                
        }
    }

只有一个异常被抛出,其他任务发生了什么?此外,Console.WriteLine("Task Cancelled") 从未执行。
输出:
Starting application
Executing task1 ...
Executing task2 ...
Executing task2 ...
Executing task1 ...
Executing task1 ...
Executing task2 ...
Executing task2 ...
Executing task1 ...
Aggregate Exception occurred
A task was canceled.
Finish Application
1个回答

3

两件事:

  1. 你应该调用ex.Flatten().InnerExceptions,请参考this
  2. Task.Delay抛出异常而不是取消操作。尝试使用try catch进行日志记录。或者,你可以不将token传递给Task.Delay

如果你没有将CancellationToken传递给Task.Delay,那么你就有点忽略了拥有CancellationToken的意义。 - Joe White
@JoeWhite,我想你说得有道理,建议是为了确保使用取消处理逻辑。 - mrtig
@mrtig 这很有帮助,但这是否意味着一旦发出取消标记,所有任务都会被正确终止? - Wahab Akhtar
2
@WahabAkhtar 正确的取消操作是由您的逻辑进行协商的 - 无论是退出循环还是抛出异常。只有在具备处理它的逻辑时才会执行取消操作,其中包括将令牌传递给“Task.Delay”。 - mrtig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接