Anulowanie zadania

Klasy System.Threading.Tasks.Task i System.Threading.Tasks.Task<TResult> obsługują anulowanie przy użyciu tokenów anulowania. Aby uzyskać więcej informacji, zobacz Anulowanie w zarządzanych wątkach. W klasach Task anulowanie obejmuje współpracę między pełnomocnikiem użytkownika, który reprezentuje operację, którą można anulować, oraz kod, który zażądał anulowania. Pomyślne anulowanie obejmuje żądanie kodu wywołującego CancellationTokenSource.Cancel metodę, a użytkownik deleguje zakończenie operacji w odpowiednim czasie. Można zakończyć operację przy użyciu jednej z następujących opcji:

  • Wracając z delegata. W wielu scenariuszach ta opcja jest wystarczająca. Jednak wystąpienie zadania, które zostało anulowane w ten sposób, przechodzi do TaskStatus.RanToCompletion stanu, a nie do TaskStatus.Canceled stanu.

  • Przez zgłoszenie elementu OperationCanceledException i przekazanie go tokenu, na którym zażądano anulowania. Preferowanym sposobem wykonania jest użycie ThrowIfCancellationRequested metody . Zadanie, które zostało anulowane w ten sposób, przechodzi do stanu Anulowano, którego kod wywołujący może użyć do sprawdzenia, czy zadanie odpowiedziało na żądanie anulowania.

W poniższym przykładzie przedstawiono podstawowy wzorzec anulowania zadania, który zgłasza wyjątek:

Uwaga

Token jest przekazywany do delegata użytkownika i wystąpienia zadania.

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

Pełny przykład można znaleźć w temacie How to: Cancel a Task and Its Children (Jak anulować zadanie i jego elementy podrzędne).

Gdy wystąpienie zadania obserwuje OperationCanceledException zgłoszony przez kod użytkownika, porównuje token wyjątku z skojarzonym tokenem (tym, który został przekazany do interfejsu API, który utworzył zadanie). Jeśli tokeny są takie same, a właściwość tokenu IsCancellationRequested zwraca truewartość , zadanie interpretuje to jako potwierdzenie anulowania i przejścia do stanu Anulowane. Jeśli nie używasz Wait metody lub WaitAll do oczekiwania na zadanie, zadanie po prostu ustawia jego stan na Canceled.

Jeśli czekasz na zadanie, które przechodzi do stanu Anulowano, System.Threading.Tasks.TaskCanceledException zgłaszany jest wyjątek (opakowany w AggregateException wyjątek). Ten wyjątek wskazuje pomyślne anulowanie zamiast wadliwej sytuacji. W związku z tym właściwość zadania Exception zwraca wartość null.

Jeśli właściwość tokenu IsCancellationRequested zwraca false wartość lub token wyjątku nie jest zgodny z tokenem zadania, OperationCanceledException element jest traktowany jak normalny wyjątek, powodując przejście zadania do stanu Błąd. Obecność innych wyjątków spowoduje również przejście zadania do stanu Błąd. Stan ukończonego zadania można uzyskać we Status właściwości .

Istnieje możliwość, że zadanie może nadal przetwarzać niektóre elementy po żądaniu anulowania.

Zobacz też