取消工作

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 類別會使用取消語彙基元支援取消。 如需詳細資訊,請參閱受控執行緒中的取消作業。 在 Task 類別中,取消作業包括使用者委派之間的合作,這是指可取消的作業和要求取消的程式碼。 成功的取消作業包括要求呼叫 CancellationTokenSource.Cancel 方法的程式碼,以及適時終止作業的使用者委派。 您可以使用下列選項之一來終止作業:

  • 藉由從委派傳回。 在許多情況下,此選項就已足夠。 不過,以這種方式取消的工作執行個體將會轉換至 TaskStatus.RanToCompletion 狀態,而非 TaskStatus.Canceled 狀態。

  • 透過擲回 OperationCanceledException,並將其傳遞至據以要求取消的語彙基元。 執行此作業的常見方式是使用 ThrowIfCancellationRequested 方法。 以此方式取消的工作會轉換至 Canceled 狀態,可供呼叫端節點用以驗證工作已回應其取消要求。

下列範例說明會擲回例外狀況的工作取消基本模式:

注意

語彙基元不但會傳遞至使用者委派,也會傳遞至工作執行個體。

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,則工作會將此解譯成確認取消,並轉換至 Canceled 狀態。 如果未使用 WaitWaitAll 方法等候工作,則工作只會將其狀態設為 Canceled

如果您正在等候轉換至 Canceled 狀態的工作,則會擲回 System.Threading.Tasks.TaskCanceledException 例外狀況 (包裝在 AggregateException 例外狀況中)。 請注意,此例外狀況表示取消成功,而非錯誤情況。 因此,工作的 Exception 屬性會傳回 null

如果語彙基元的 IsCancellationRequested 屬性傳回 false,或例外狀況的語彙基元不符合工作的語彙基元,則 OperationCanceledException 會被視為一般例外狀況,而使工作轉換至 Faulted 狀態。 如有其他例外狀況存在,也會使工作轉換至 Faulted 狀態。 您可以在 Status 屬性中取得已完成工作的狀態。

在要求取消之後,工作仍有可能會繼續處理某些項目。

另請參閱