Delen via


Taakannulering

De System.Threading.Tasks.Task en System.Threading.Tasks.Task<TResult> klassen ondersteunen annulering met behulp van annuleringstokens. Zie Annulering in Beheerde threadsvoor meer informatie. In de taakklassen omvat annulering de samenwerking tussen de gemachtigde van de gebruiker, die een annuleringsbewerking vertegenwoordigt en de code die de annulering heeft aangevraagd. Een geslaagde annulering omvat de verzoekcode die de CancellationTokenSource.Cancel methode aanroept en de gebruikersdelegate die de bewerking tijdig beëindigt. U kunt de bewerking beëindigen met behulp van een van de volgende opties:

  • Door terug te keren van de gemachtigde. In veel scenario's is deze optie voldoende. Een taakexemplaar dat op deze manier wordt geannuleerd, wordt echter overgebracht naar de TaskStatus.RanToCompletion toestand, niet naar de TaskStatus.Canceled toestand.

  • Door een OperationCanceledException te gooien en het token door te geven waarop annulering is aangevraagd. De voorkeursmethode die u kunt uitvoeren, is door de ThrowIfCancellationRequested methode te gebruiken. Een taak die op deze manier wordt geannuleerd, wordt overgezet naar de status Geannuleerd, die door de aanroepcode kan worden gebruikt om te controleren of de taak heeft gereageerd op de annuleringsaanvraag.

In het volgende voorbeeld ziet u het basispatroon voor taakannulering waarmee de uitzondering wordt gegenereerd:

Opmerking

Het token wordt doorgegeven aan de gedelegeerde van de gebruiker en de taakinstantie.

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

Voor een volledig voorbeeld, zie Hoe een taak en zijn subtaken te annuleren.

Wanneer een taakexemplaar een door de gebruikerscode opgegooide uitzondering observeert, vergelijkt het het token van de uitzondering met het bijbehorende token (het token dat is doorgegeven aan de API die de taak heeft gemaakt). Als de tokens hetzelfde zijn en de eigenschap van het token IsCancellationRequested retourneert, interpreteert de taak dit als bevestiging van annulering en gaat naar de toestand Geannuleerd. Als u geen Wait- of WaitAll-methode gebruikt om te wachten op de taak, dan stelt de taak de status ervan in op Canceled.

Als u wacht op een taak die overgaat naar de status Geannuleerd, wordt er een System.Threading.Tasks.TaskCanceledException uitzondering (verpakt in een AggregateException uitzondering) gegenereerd. Deze uitzondering geeft aan dat de annulering is geslaagd in plaats van een foutieve situatie. Daarom retourneert de eigenschap van de taak Exceptionnull.

Als de eigenschap van token IsCancellationRequestedfalse retourneert of als het token van de uitzondering niet overeenkomt met het token van de taak, wordt de OperationCanceledException behandeld als een normale uitzondering, waardoor de taak naar de toestand Mislukt overgaat. De aanwezigheid van andere uitzonderingen zorgt er ook voor dat de taak overgaat naar de status Mislukt. U kunt de status van de voltooide taak in de Status eigenschap ophalen.

Het is mogelijk dat een taak bepaalde items blijft verwerken nadat de annulering is aangevraagd.

Zie ook