工作取消Task Cancellation

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 類別可使用 .NET Framework 中的取消語彙基元來支援取消作業。The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> classes support cancellation through the use of cancellation tokens in the .NET Framework. 如需詳細資訊,請參閱受控執行緒中的取消作業For more information, see Cancellation in Managed Threads. 在 Task 類別中,取消作業包括使用者委派之間的合作,這是指可取消的作業和要求取消的程式碼。In the Task classes, cancellation involves cooperation between the user delegate, which represents a cancelable operation and the code that requested the cancellation. 成功的取消作業包括要求呼叫 CancellationTokenSource.Cancel 方法的程式碼,以及適時終止作業的使用者委派。A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method, and the user delegate terminating the operation in a timely manner. 您可以使用下列選項之一來終止作業:You can terminate the operation by using one of these options:

  • 藉由直接從委派傳回。By simply returning from the delegate. 在許多情況下使用這個選項即已足夠,但以這種方式取消的工作執行個體將會轉換至 TaskStatus.RanToCompletion 狀態,而非 TaskStatus.Canceled 狀態。In many scenarios this is sufficient; however, a task instance that is canceled in this way transitions to the TaskStatus.RanToCompletion state, not to the TaskStatus.Canceled state.

  • 擲回 OperationCanceledException ,並將其傳遞至據以要求取消的語彙基元。By throwing a OperationCanceledException and passing it the token on which cancellation was requested. 執行此作業的常見方式是使用 ThrowIfCancellationRequested 方法。The preferred way to do this is to use the ThrowIfCancellationRequested method. 以此方式取消的工作會切換至 Canceled 狀態,可供呼叫端節點用以驗證工作已回應其取消要求。A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request.

下列範例說明會擲回例外狀況的工作取消基本模式。The following example shows the basic pattern for task cancellation that throws the exception. 請注意,語彙基元不但會傳遞至使用者委派,也會傳遞至工作執行個體本身。Note that the token is passed to the user delegate and to the task instance itself.

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

如需更完整的範例,請參閱如何: 取消工作及其子系For a more complete example, see How to: Cancel a Task and Its Children.

工作執行個體在觀察到由使用者程式碼擲回的 OperationCanceledException 時,會比較此例外狀況的語彙基元及與它自己相關聯的語彙基元 (即傳遞給建立工作之 API 的語彙基元)。When a task instance observes an OperationCanceledException thrown by user code, it compares the exception's token to its associated token (the one that was passed to the API that created the Task). 如果兩者相同,且此語彙基元的 IsCancellationRequested 屬性傳回 true,則工作會將此解譯成確認取消,並轉換至 Canceled 狀態。If they are the same and the token's IsCancellationRequested property returns true, the task interprets this as acknowledging cancellation and transitions to the Canceled state. 如果未使用 WaitWaitAll 方法等候工作,則工作只會將其狀態設為 CanceledIf you do not use a Wait or WaitAll method to wait for the task, then the task just sets its status to Canceled.

如果您正在等候轉換至 Canceled 狀態的工作,則會擲回 System.Threading.Tasks.TaskCanceledException 例外狀況 (包含在 AggregateException 例外狀況中)。If you are waiting on a Task that transitions to the Canceled state, a System.Threading.Tasks.TaskCanceledException exception (wrapped in an AggregateException exception) is thrown. 請注意,此例外狀況表示取消成功,而非錯誤情況。Note that this exception indicates successful cancellation instead of a faulty situation. 因此,工作的 Exception 屬性會傳回 nullTherefore, the task's Exception property returns null.

如果語彙基元的 IsCancellationRequested 屬性傳回 false,或例外狀況的語彙基元不符合工作的語彙基元,則 OperationCanceledException 會被視為一般例外狀況,而使工作轉換至 Faulted 狀態。If the token's IsCancellationRequested property returns false or if the exception's token does not match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state. 同時也請注意,如有其他例外狀況存在,也會使工作轉換至 Faulted 狀態。Also note that the presence of other exceptions will also cause the Task to transition to the Faulted state. 您可以在 Status 屬性中取得已完成工作的狀態。You can get the status of the completed task in the Status property.

不過,在要求取消之後,工作仍有可能會繼續處理某些項目。It is possible that a task may continue to process some items after cancellation is requested.

請參閱See also