OperationCanceledException VS TaskCanceledException when task is canceled

后端 未结 2 499
鱼传尺愫
鱼传尺愫 2021-02-07 04:19

The following code creates a task which is being canceled. await expression (case 1) throws System.OperationCanceledException while synchronous W

相关标签:
2条回答
  • 2021-02-07 04:25

    The difference here comes from using token.ThrowIfCancellationRequested(). This method checks for cancellation and if requested throws OperationCanceledException specifically and not TaskCanceledException (understandable as CancellationToken isn't exclusive to the TPL). You can look at the reference source and see that it calls this method:

    private void ThrowOperationCanceledException()
    {
        throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
    }
    

    "Regular" cancellation though will indeed generate a TaskCanceledException. You can see that by cancelling the token before the task had a chance to start running:

    cancellationTokenSource.Cancel();
    var task = Task.Run(() => { }, cancellationTokenSource.Token);
    try
    {
        await task; 
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        Console.WriteLine($"Task.IsCanceled: {task.IsCanceled}");
        Console.WriteLine($"Task.IsFaulted: {task.IsFaulted}");
        Console.WriteLine($"Task.Exception: {((task.Exception == null) ? "null" : task.Exception.ToString())}");
    }
    

    Output:

    System.Threading.Tasks.TaskCanceledException: A task was canceled.
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
       at Sandbox.Program.<MainAsync>d__1.MoveNext()
    Task.IsCanceled: True
    Task.IsFaulted: False
    Task.Exception: null
    

    Traditional .Net methods usually don't use CancellationToken.ThrowIfCancellationRequested for async API as this is only appropriate when offloading work to another thread. These methods are for inherently asynchronous operations so cancellation is monitored using CancellationToken.Register (or the internal InternalRegisterWithoutEC).

    0 讨论(0)
  • 2021-02-07 04:37

    TaskCanceledException inherits from OperationCanceledException. So it least there is a little consitency.

    So flatten AggregateException and compare with base should be consistent.

    var ex = exception.Flatten()
    if( ex is OperationCanceledException)
    {
    ...
    }
    
    0 讨论(0)
提交回复
热议问题