语言

任务取消

System.Threading.Tasks.Task 和 System.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,则任务会将此项解释为确认取消并转换为“已取消”状态。 如果不使用 Wait 或 WaitAll 方法等待任务,则任务只会将其状态设置为 Canceled。

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

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

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

另请参阅