Cancelación de tareasTask Cancellation

Las clases System.Threading.Tasks.Task y System.Threading.Tasks.Task<TResult> admiten la cancelación a través del uso de tokens de cancelación en .NET Framework.The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> classes support cancellation through the use of cancellation tokens in the .NET Framework. Para más información, consulte el tema sobre la cancelación en subprocesos administrados.For more information, see Cancellation in Managed Threads. En las clases Task, la cancelación implica la cooperación entre el delegado de usuario, que representa una operación que se puede cancelar y el código que solicitó la cancelación.In the Task classes, cancellation involves cooperation between the user delegate, which represents a cancelable operation and the code that requested the cancellation. Una cancelación correcta significa que el código que la solicita llama al método CancellationTokenSource.Cancel y que el delegado de usuario finaliza la operación a tiempo.A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method, and the user delegate terminating the operation in a timely manner. Puede finalizar la operación a través de una de estas opciones:You can terminate the operation by using one of these options:

  • Devolver simplemente un valor del delegado.By simply returning from the delegate. En muchos escenarios esto es suficiente; sin embargo, una instancia de tarea cancelada de esta manera cambia al estado TaskStatus.RanToCompletion , no al estado TaskStatus.Canceled .In many scenarios this is sufficient; however, a task instance that is canceled in this way transitions to the TaskStatus.RanToCompletion state, not to the TaskStatus.Canceled state.

  • Producir una excepción OperationCanceledException y pasarle el token en el que se solicitó la cancelación.By throwing a OperationCanceledException and passing it the token on which cancellation was requested. En este caso, se prefiere usar el método ThrowIfCancellationRequested .The preferred way to do this is to use the ThrowIfCancellationRequested method. Una tarea cancelada de esta manera cambia al estado Canceled, que sirve al código que realiza la llamada para comprobar que la tarea respondió a su solicitud de cancelación.A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request.

En el siguiente ejemplo se muestra el modelo básico para la opción de cancelación de tareas que produce la excepción.The following example shows the basic pattern for task cancellation that throws the exception. Observe que el token se pasa al delegado de usuario y a la propia instancia de la tarea.Note that the token is passed to the user delegate and to the task instance itself.

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

Para obtener un ejemplo más completo, vea Cómo: Cancelar una tarea y sus elementos secundarios.For a more complete example, see How to: Cancel a Task and Its Children.

Cuando una instancia de tarea observa una excepción OperationCanceledException iniciada desde el código de usuario, compara el token de la excepción con su token asociado (el que se pasó a la API que creó la tarea).When a task instance observes an OperationCanceledException thrown by user code, it compares the exception's token to its associated token (the one that was passed to the API that created the Task). Si son iguales y la propiedad IsCancellationRequested del token devuelve true, la tarea lo interpreta como una confirmación de cancelación y pasa al estado Canceled.If they are the same and the token's IsCancellationRequested property returns true, the task interprets this as acknowledging cancellation and transitions to the Canceled state. Si no se usa un método Wait o WaitAll para esperar a la tarea, esta simplemente establece su estado en Canceled.If you do not use a Wait or WaitAll method to wait for the task, then the task just sets its status to Canceled.

Si espera en un elemento Task que cambia al estado “Canceled”, se crea y se inicia una excepción System.Threading.Tasks.TaskCanceledException (encapsulada en la excepción AggregateException ).If you are waiting on a Task that transitions to the Canceled state, a System.Threading.Tasks.TaskCanceledException exception (wrapped in an AggregateException exception) is thrown. Observe que esta excepción indica la cancelación correcta en lugar de una situación de error.Note that this exception indicates successful cancellation instead of a faulty situation. Por consiguiente, la propiedad Exception del elemento Task devuelve null.Therefore, the task's Exception property returns null.

Si la propiedad IsCancellationRequested del token devuelve False o si el token de la excepción no coincide con el token de la tarea, OperationCanceledException se trata como una excepción normal, por lo que la tarea cambia al estado Faulted.If the token's IsCancellationRequested property returns false or if the exception's token does not match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state. Observe también que la presencia de otras excepciones también hará que la tarea pase al estado Faulted.Also note that the presence of other exceptions will also cause the Task to transition to the Faulted state. Puede obtener el estado de la tarea completada en la propiedad Status .You can get the status of the completed task in the Status property.

Es posible que una tarea continúe procesando algunos elementos una vez solicitada la cancelación.It is possible that a task may continue to process some items after cancellation is requested.

Vea tambiénSee also