任务取消

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 类通过使用取消令牌来支持取消。 有关详细信息,请参阅托管线程中的取消。 在 Task 类中,取消涉及用户委托(表示可取消作)和请求取消的代码之间的合作。 成功取消涉及调用 CancellationTokenSource.Cancel 方法的请求代码,以及及时终止操作的用户委托。 可以使用以下选项之一终止操作:

以下示例显示了引发异常的任务取消的基本模式:

注释

标记将传递到用户委托和任务实例。

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Run(() =>
        {
            // Were we already canceled?
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do
                // other cleanup before throwing.
                if (ct.IsCancellationRequested)
                {
                    // Clean up here, then...
                    ct.ThrowIfCancellationRequested();
                }
            }
        }, tokenSource2.Token); // Pass same token to Task.Run.

        tokenSource2.Cancel();

        // Just continue on this thread, or await with try-catch:
        try
        {
            await task;
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
        }
        finally
        {
            tokenSource2.Dispose();
        }

        Console.ReadKey();
    }
}
Imports System.Threading
Imports System.Threading.Tasks

Module Test
    Sub Main()
        Dim tokenSource2 As New CancellationTokenSource()
        Dim ct As CancellationToken = tokenSource2.Token

        Dim t2 = Task.Factory.StartNew(Sub()
                                           ' Were we already canceled?
                                           ct.ThrowIfCancellationRequested()

                                           Dim moreToDo As Boolean = True
                                           While moreToDo = True
                                               ' Poll on this property if you have to do
                                               ' other cleanup before throwing.
                                               If ct.IsCancellationRequested Then

                                                   ' Clean up here, then...
                                                   ct.ThrowIfCancellationRequested()
                                               End If

                                           End While
                                       End Sub _
        , tokenSource2.Token) ' Pass same token to StartNew.

        ' Cancel the task.
        tokenSource2.Cancel()

        ' Just continue on this thread, or Wait/WaitAll with try-catch:
        Try
            t2.Wait()

        Catch e As AggregateException

            For Each item In e.InnerExceptions
                Console.WriteLine(e.Message & " " & item.Message)
            Next
        Finally
            tokenSource2.Dispose()
        End Try

        Console.ReadKey()
    End Sub
End Module

有关完整示例,请参阅 如何取消任务及其子任务

当任务实例观察到由用户代码引发的OperationCanceledException时,它会将异常的令牌与其关联的令牌(即传递给创建任务的API的令牌)进行比较。 如果令牌相同,并且令牌 IsCancellationRequested 的属性返回 true,则任务会将此项解释为确认取消并转换为“已取消”状态。 如果不使用 WaitWaitAll 方法等待任务,则任务只会将其状态设置为 Canceled

如果在等待的任务转换为“已取消”状态,就会引发 System.Threading.Tasks.TaskCanceledException 异常(包装在 AggregateException 异常中)。 此异常表示成功取消,而不是出错的情况。 因此,任务 Exception 的属性返回 null

如果令牌 IsCancellationRequested 的属性返回 false 或异常的令牌与 Task 的令牌不匹配,则 OperationCanceledException 被视为正常异常,导致任务转换为错误状态。 存在其他异常也会导致任务过渡到故障状态。 可以在属性中 Status 获取已完成任务的状态。

在请求取消操作之后,任务可能还会继续处理一些项。

另请参阅