任务取消

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 类支持通过使用取消标记(.NET Framework 4 中的新功能)进行取消。 有关更多信息,请参见取消。 在 Task 类中,取消涉及用户委托(表示可取消的操作)和请求取消的代码之间的合作。成功的取消涉及以下过程:请求代码调用 CancellationTokenSource.Cancel 方法,用户委托及时终止操作。 可以使用以下选项之一终止操作:

  • 简单地从委托中返回。 在许多情况下,这样已足够;但是,采用这种方式“取消”的任务实例会转换为 RanToCompletion 状态,而不是 Canceled 状态。

  • 引发 OperationCanceledException,并将其传递到在其上请求了取消的标记。 完成此操作的首选方式是使用 ThrowIfCancellationRequested 方法。 采用这种方式取消的任务会转换为 Canceled 状态,调用代码可使用该状态来验证任务是否响应了其取消请求。

下面的示例演示引发异常的任务取消的基本模式。 请注意,标记将传递到用户委托和任务实例本身。

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
        End Try

        Console.ReadKey()
    End Sub
End Module
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // 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 StartNew.

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch:
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }

        Console.ReadKey();
    }
}

有关更完整的示例,请参见 如何:取消任务及其子级

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

如果您在等待转换为 Canceled 状态的任务,则会生成并引发 TaskCanceledException(包装在 AggregateException 中)。 请注意,此异常指示成功的取消,而不是有错误的情况。 因此,任务的 Exception 属性返回 null。

如果标记的 IsCancellationRequested 属性返回 false,或者异常的标记与任务的标记不匹配,则会将 OperationCanceledException 按照普通的异常来处理,从而导致任务转换为 Faulted 状态。 另外还要注意,其他异常的存在将也会导致任务转换为 Faulted 状态。 您可以在 Status 属性中获取已完成任务的状态。

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

请参见

任务

如何:取消任务及其子级

概念

取消