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 threads voor 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 aanvraagcode die de CancellationTokenSource.Cancel methode aanroept en de gebruiker delegeert 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 taakexemplaren die op deze manier worden geannuleerd, worden echter overgezet naar de TaskStatus.RanToCompletion status, niet naar de TaskStatus.Canceled status.

  • Door een OperationCanceledException en doorgeven van het token 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:

Notitie

Het token wordt doorgegeven aan de gemachtigde van de gebruiker en het taakexemplaren.

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

Zie Voor een volledig voorbeeld: Een taak en de onderliggende items annuleren.

Wanneer een taakexemplaar een OperationCanceledException door de gebruikerscode gegenereerde gegevens bekijkt, wordt het token van de uitzondering vergeleken 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 IsCancellationRequested het token wordt geretourneerd true, interpreteert de taak dit als bevestiging van annulering en overgangen naar de status Geannuleerd. Als u geen of methode gebruikt Wait om te wachten op de taak, stelt de taak de status ervan in op Canceled.WaitAll

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 wordt de eigenschap van Exception de taak geretourneerd null.

Als de eigenschap van IsCancellationRequested het token wordt geretourneerd false of als het token van de uitzondering niet overeenkomt met het token van de taak, wordt de OperationCanceledException taak behandeld als een normale uitzondering, waardoor de taak wordt overgezet naar de status Mislukt. 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