Condividi tramite


Annullamento attività

Le System.Threading.Tasks.Task classi e System.Threading.Tasks.Task<TResult> supportano l'annullamento usando i token di annullamento. Per altre informazioni, vedere Annullamento nei thread gestiti. Nelle classi Task l'annullamento comporta la cooperazione tra il delegato utente, che rappresenta un'operazione annullabile e il codice che ha richiesto l'annullamento. Per un annullamento riuscito, il codice richiedente deve chiamare il metodo CancellationTokenSource.Cancel, e il delegato dell'utente deve terminare l'operazione in modo tempestivo. È possibile terminare l'operazione usando una di queste opzioni:

  • Restituito da parte del delegato. In molti scenari, questa opzione è sufficiente. Tuttavia, un'istanza dell'attività annullata in questo modo passa nello stato TaskStatus.RanToCompletion, non nello stato TaskStatus.Canceled.

  • Generando un oggetto OperationCanceledException e passandogli il token per cui è stato richiesto l'annullamento. Il modo migliore per eseguire consiste nell'usare il ThrowIfCancellationRequested metodo . Un'attività annullata in questo modo passa allo stato Annullato, che il codice chiamante può usare per verificare che l'attività abbia risposto alla richiesta di annullamento.

L'esempio seguente illustra il modello di base per l'annullamento delle attività che genera l'eccezione:

Annotazioni

Il token viene passato al delegato dell'utente e all'istanza del compito.

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

Per un esempio completo, vedere Procedura: Annullare un'attività e i relativi figli.

Quando un'istanza dell'attività osserva un'eccezione OperationCanceledException generata dal codice utente, confronta il token dell'eccezione con il token associato (quello passato all'API che ha creato l'attività). Se i token sono uguali e la proprietà del IsCancellationRequested token restituisce true, l'attività lo interpreta come conferma dell'annullamento e passa allo stato Annullato. Se non si usa un metodo Wait o WaitAll per attendere l'attività, l'attività cambia semplicemente il suo stato in Canceled.

Se stai aspettando un'attività che passa allo stato annullato, viene generata un'eccezione System.Threading.Tasks.TaskCanceledException (incapsulata in un'eccezione AggregateException). Questa eccezione indica l'annullamento riuscito anziché una situazione difettosa. Di conseguenza, la proprietà dell'attività Exception restituisce null.

Se la proprietà del IsCancellationRequested token restituisce false o se il token dell'eccezione non corrisponde al token dell'attività, viene OperationCanceledException considerato come un'eccezione normale, causando la transizione dell'attività allo stato Faulted. La presenza di altre eccezioni causerà anche la transizione della task allo stato di errore. È possibile ottenere lo stato dell'attività completata nella Status proprietà .

È possibile che un'attività continui a elaborare alcuni elementi dopo la richiesta di annullamento.

Vedere anche