How to cancel a Task in await?

后端 未结 4 1341
孤独总比滥情好
孤独总比滥情好 2020-11-22 15:20

I\'m playing with these Windows 8 WinRT tasks, and I\'m trying to cancel a task using the method below, and it works to some point. The CancelNotification method DOES get ca

4条回答
  •  有刺的猬
    2020-11-22 15:29

    One case which hasn't been covered is how to handle cancellation inside of an async method. Take for example a simple case where you need to upload some data to a service get it to calculate something and then return some results.

    public async Task ProcessDataAsync(MyData data)
    {
        var client = await GetClientAsync();
        await client.UploadDataAsync(data);
        await client.CalculateAsync();
        return await client.GetResultsAsync();
    }
    

    If you want to support cancellation then the easiest way would be to pass in a token and check if it has been cancelled between each async method call (or using ContinueWith). If they are very long running calls though you could be waiting a while to cancel. I created a little helper method to instead fail as soon as canceled.

    public static class TaskExtensions
    {
        public static async Task WaitOrCancel(this Task task, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            await Task.WhenAny(task, token.WhenCanceled());
            token.ThrowIfCancellationRequested();
    
            return await task;
        }
    
        public static Task WhenCanceled(this CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource();
            cancellationToken.Register(s => ((TaskCompletionSource)s).SetResult(true), tcs);
            return tcs.Task;
        }
    }
    

    So to use it then just add .WaitOrCancel(token) to any async call:

    public async Task ProcessDataAsync(MyData data, CancellationToken token)
    {
        Client client;
        try
        {
            client = await GetClientAsync().WaitOrCancel(token);
            await client.UploadDataAsync(data).WaitOrCancel(token);
            await client.CalculateAsync().WaitOrCancel(token);
            return await client.GetResultsAsync().WaitOrCancel(token);
        }
        catch (OperationCanceledException)
        {
            if (client != null)
                await client.CancelAsync();
            throw;
        }
    }
    

    Note that this will not stop the Task you were waiting for and it will continue running. You'll need to use a different mechanism to stop it, such as the CancelAsync call in the example, or better yet pass in the same CancellationToken to the Task so that it can handle the cancellation eventually. Trying to abort the thread isn't recommended.

提交回复
热议问题