Partager via


Annulation de tâches

Les classes System.Threading.Tasks.Task et System.Threading.Tasks.Task<TResult> prennent en charge l'annulation via l'utilisation de jetons d'annulation, nouveaux dans le .NET Framework 4. Pour plus d'informations, consultez Annulation. Dans les classes Task, l'annulation implique une coopération entre le délégué utilisateur, qui représente une opération annulable, et le code qui a demandé l'annulation. Une annulation réussie implique le code demandeur qui appelle la méthode CancellationTokenSource.Cancel et le délégué d'utilisateur qui termine l'opération en temps voulu. Vous pouvez terminer l'opération à l'aide de l'une des options suivantes :

  • Par un retour du délégué. Cela suffit dans la plupart des scénarios ; toutefois, une instance de tâche annulée de cette façon passe à l'état RanToCompletion, et non à l'état Canceled.

  • En levant une OperationCanceledException et en lui passant le jeton sur lequel l'annulation a été demandée. La meilleure façon de faire cela est d'utiliser la méthode ThrowIfCancellationRequested. Une tâche annulée de cette façon passe à l'état Canceled, ce que le code appelant peut utiliser pour vérifier que la tâche a répondu à sa requête d'annulation.

L'exemple suivant montre le modèle de base d'annulation de tâche qui lève l'exception. Notez que le jeton est passé au délégué utilisateur et à l'instance de tâche.

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
        End Try

        Console.ReadKey()
    End Sub
End Module
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // 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 StartNew.

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch:
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }

        Console.ReadKey();
    }
}

Pour un exemple plus complet, consultez Comment : annuler une tâche et ses enfants.

Lorsqu'une instance de tâche observe une OperationCanceledException levée par le code utilisateur, elle compare le jeton de l'exception à son jeton associé (celui passé à l'API ayant créé la tâche). S'ils sont identiques et si la propriété IsCancellationRequested du jeton retourne la valeur true, la tâche l'interprète comme une acceptation d'annulation et passe à l'état Canceled. Si vous n'utilisez pas une méthode Wait ou WaitAll pour attendre la tâche, la tâche définit uniquement son état sur Canceled.

Si vous attendez une tâche qui passe à l'état Canceled, une TaskCanceledException (incluse dans un wrapper dans AggregateException) est fabriquée et levée. Notez que cette exception indique une annulation réussie et non une défaillance. Par conséquent, la propriété Exception de la tâche retourne null.

Si la propriété IsCancellationRequested du jeton retourne la valeur false ou si le jeton de l'exception ne correspond pas au jeton de la tâche, OperationCanceledException est traitée comme une exception normale, entraînant ainsi le passage de la tâche à l'état Faulted. Notez également que la présence d'autres exceptions entraînera le passage de la tâche à l'état Faulted. Vous pouvez obtenir l'état de la tâche terminée dans la propriété Status.

Il est possible qu'une tâche puisse continuer à traiter certains éléments après la demande d'annulation.

Voir aussi

Tâches

Comment : annuler une tâche et ses enfants

Concepts

Annulation