Freigeben über


Vorgangsabbruch

Die System.Threading.Tasks.Task Und System.Threading.Tasks.Task<TResult> Klassen unterstützen den Abbruch mithilfe von Abbruchtoken. Weitere Informationen finden Sie unter Abbrechen in verwalteten Threads. In den Aufgabenklassen umfasst der Abbruch die Zusammenarbeit zwischen dem Benutzerdelegat, der einen abbruchfähigen Vorgang darstellt, und dem Code, der den Abbruch angefordert hat. Ein erfolgreicher Abbruch erfolgt, wenn der anfordernde Code die CancellationTokenSource.Cancel-Methode aufruft und der Benutzerdelegat den Vorgang rechtzeitig beendet. Sie können den Vorgang mit einer der folgenden Optionen beenden:

  • Durch eine Rückkehr vom Delegaten. In vielen Szenarien reicht diese Option aus. Eine Vorgangsinstanz, die auf diese Weise abgebrochen wird, wechselt jedoch in den TaskStatus.RanToCompletion Zustand, nicht in den TaskStatus.Canceled Zustand.

  • Durch Auslösen einer OperationCanceledException und Übergeben des Tokens, in dem der Abbruch angefordert wurde. Die bevorzugte Vorgehensweise ist die Nutzung der ThrowIfCancellationRequested Methode. Eine Aufgabe, die auf diese Weise abgebrochen wird, wechselt in den Zustand "Abgebrochen", mit dem der aufrufende Code überprüfen kann, ob die Aufgabe auf ihre Abbruchanforderung geantwortet hat.

Das folgende Beispiel zeigt das grundlegende Muster für den Abbruch von Vorgängen, das die Ausnahme auslöst:

Hinweis

Das Token wird an den Benutzerdelegat und die Aufgabeninstanz übergeben.

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

Ein vollständiges Beispiel finden Sie unter Gewusst wie: Abbrechen einer Aufgabe und ihrer untergeordneten Elemente.

Wenn eine Aufgabeninstanz einen OperationCanceledException Vom Benutzercode ausgelösten Vorgang beobachtet, vergleicht sie das Token der Ausnahme mit dem zugehörigen Token (das Token, das an die API übergeben wurde, die die Aufgabe erstellt hat). Wenn die Token gleich sind und die IsCancellationRequested-Eigenschaft des Tokens true zurückgibt, interpretiert die Aufgabe dies als Bestätigung des Abbruchs und geht in den Zustand „Abgebrochen“ über. Wenn Sie keine Wait- oder WaitAll-Methode verwenden, um auf den Vorgang zu warten, setzt der Vorgang einfach seinen Status zu Canceled.

Wenn Sie auf eine Aufgabe warten, die in den Status "Abgebrochen" wechselt, wird eine System.Threading.Tasks.TaskCanceledException Ausnahme (eingeschlossen in eine AggregateException Ausnahme) ausgelöst. Diese Ausnahme zeigt einen erfolgreichen Abbruch anstelle einer fehlerhaften Situation an. Daher gibt die Eigenschaft Exception der Aufgabe nullzurück.

Wenn die Eigenschaft des Tokens IsCancellationRequestedfalse zurückgibt oder wenn das Token der Ausnahme nicht mit dem Token der Aufgabe übereinstimmt, wird OperationCanceledException wie eine normale Ausnahme behandelt, wodurch die Aufgabe in den Fehlerzustand wechselt. Das Vorhandensein anderer Ausnahmen führt auch dazu, dass die Aufgabe in den Fehlerhaften Zustand wechselt. Sie können den Status der abgeschlossenen Aufgabe in der Status Eigenschaft abrufen.

Es ist möglich, dass eine Aufgabe nach einer Abbruchanforderung einige Elemente weiter verarbeiten kann.

Siehe auch