简体   繁体   中英

How to handle task cancellation using ContinueWith?

I've got the following example:

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");
}

I've created a method ( DoAsync ) that does some asynchronous work and can be cancelled at any time.

As you can see Task.Run gets a cancellation token. For this reason I created continuation task with continuationOptions = TaskContinuationOptions.OnlyOnCanceled .

As a result I expected continuation task to be called only when cancellation is requested and in other cases - ignored.

But in my implementation task returned by ContinueWith throws an exception when its antecedent task is not being cancelled:

DoAsync started
DoAsync Run

Inside try-catch block
System.AggregateException...

A task was canceled.

I can fix this by adding another ContinueWith as in the example below:

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

And this code doesn't throw any exceptions.

But can I handle the cancellation using single ContinueWith properly?

The remarks for ContinueWith specifically state:

If the continuation criteria specified through the continuationOptions parameter are not met, the continuation task will be canceled instead of scheduled.

Since the criteria you specified for the antecedent weren't met, (namely, it wasn't cancelled) the continuation was set to be cancelled. You awaited the cancelled task, which therefore result in DoAsync faulting with an operation cancelled exception.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM