Exportar (0) Imprimir
Expandir todo
Este artículo proviene de un motor de traducción automática. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Cómo: Cancelar una tarea y sus elementos secundarios

En estos ejemplos se muestra cómo realizar las tareas siguientes:

  1. Crear e iniciar una tarea cancelable.

  2. Pasar un token de cancelación a un delegado de usuario y, opcionalmente, a la instancia de la tarea.

  3. Observar y responder a la solicitud de cancelación en el delegado de usuario.

  4. Opcionalmente, observar en el subproceso que realiza la llamada que la tarea se canceló.

El subproceso que realiza la llamada no finaliza la tarea forzosamente, sino que solo señala que se solicita la cancelación. Si la tarea ya se está ejecutando, es el delegado de usuario el que debe observar la solicitud y responder según corresponda. Si la cancelación se solicita antes de ejecutarse la tarea, el delegado de usuario nunca se ejecuta y el objeto de tarea pasa al estado Cancelado.

En este ejemplo se muestra cómo finalizar un objeto Task y sus elementos secundarios en respuesta a una solicitud de cancelación. También se muestra que, cuando un delegado de usuario finaliza con una excepción TaskCanceledException, el subproceso que realiza la llamada puede usar opcionalmente el método Wait o el método WaitAll para esperar a que las tareas finalicen. En este caso, se debe usar un bloque try/catch para controlar las excepciones en el subproceso que realiza la llamada.


using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      var tokenSource = new CancellationTokenSource();
      var token = tokenSource.Token;

      // Store references to the tasks so that we can wait on them and  
      // observe their status after cancellation. 
      Task t;
      var tasks = new ConcurrentBag<Task>();

      Console.WriteLine("Press any key to begin tasks...");
      Console.WriteLine("To terminate the example, press 'c' to cancel and exit...");
      Console.ReadKey();
      Console.WriteLine();

      // Request cancellation of a single task when the token source is canceled. 
      // Pass the token to the user delegate, and also to the task so it can  
      // handle the exception correctly.
      t = Task.Factory.StartNew( () => DoSomeWork(1, token), token);
      Console.WriteLine("Task {0} executing", t.Id);
      tasks.Add(t);

      // Request cancellation of a task and its children. Note the token is passed 
      // to (1) the user delegate and (2) as the second argument to StartNew, so  
      // that the task instance can correctly handle the OperationCanceledException.
      t = Task.Factory.StartNew( () => {
                                     // Create some cancelable child tasks.  
                                     Task tc;
                                     for (int i = 3; i <= 10; i++) {
                                        // For each child task, pass the same token 
                                        // to each user delegate and to StartNew.
                                        tc = Task.Factory.StartNew( iteration => DoSomeWork((int)iteration, token), i, token);
                                        Console.WriteLine("Task {0} executing", tc.Id);
                                        tasks.Add(tc);
                                        // Pass the same token again to do work on the parent task.  
                                        // All will be signaled by the call to tokenSource.Cancel below.
                                        DoSomeWork(2, token);
                                     } 
                                  }, 
                                  token);

        Console.WriteLine("Task {0} executing", t.Id);
        tasks.Add(t);

        // Request cancellation from the UI thread. 
        if (Console.ReadKey().KeyChar == 'c') {
            tokenSource.Cancel();
            Console.WriteLine("\nTask cancellation requested.");

            // Optional: Observe the change in the Status property on the task. 
            // It is not necessary to wait on tasks that have canceled. However, 
            // if you do wait, you must enclose the call in a try-catch block to 
            // catch the TaskCanceledExceptions that are thrown. If you do  
            // not wait, no exception is thrown if the token that was passed to the  
            // StartNew method is the same token that requested the cancellation. 
        } 

        try {
            Task.WaitAll(tasks.ToArray());
        }
        catch (AggregateException e) {
           Console.WriteLine("\nAggregateException thrown with the following inner exceptions:");
           // Display information about each exception. 
           foreach (var v in e.InnerExceptions) {
              if (v is TaskCanceledException)
                 Console.WriteLine("   TaskCanceledException: Task {0}", 
                                   ((TaskCanceledException) v).Task.Id);
              else
                 Console.WriteLine("   Exception: {0}", v.GetType().Name);
           } 
           Console.WriteLine();
        } 

        // Display status of all tasks. 
        foreach (var task in tasks)
            Console.WriteLine("Task {0} status is now {1}", task.Id, task.Status);
   }

   static void DoSomeWork(int taskNum, CancellationToken ct)
   {
      // Was cancellation already requested? 
      if (ct.IsCancellationRequested == true) {
         Console.WriteLine("Task {0} was cancelled before it got started.",
                           taskNum);
         ct.ThrowIfCancellationRequested();
      } 

      int maxIterations = 100;

      // NOTE!!! A "TaskCanceledException was unhandled 
      // by user code" error will be raised here if "Just My Code" 
      // is enabled on your computer. On Express editions JMC is 
      // enabled and cannot be disabled. The exception is benign. 
      // Just press F5 to continue executing your code. 
      for (int i = 0; i <= maxIterations; i++) {
         // Do a bit of work. Not too much. 
         var sw = new SpinWait();
         for (int j = 0; j <= 100; j++)
            sw.SpinOnce();

         if (ct.IsCancellationRequested) {
            Console.WriteLine("Task {0} cancelled", taskNum);
            ct.ThrowIfCancellationRequested();
         } 
      } 
   } 
}  
// The example displays output like the following:
//       Press any key to begin tasks...
//    To terminate the example, press 'c' to cancel and exit...
//    
//    Task 1 executing
//    Task 2 executing
//    Task 3 executing
//    Task 4 executing
//    Task 5 executing
//    Task 6 executing
//    Task 7 executing
//    Task 8 executing
//    c
//    Task cancellation requested.
//    Task 2 cancelled
//    Task 7 cancelled
//    
//    AggregateException thrown with the following inner exceptions:
//       TaskCanceledException: Task 2
//       TaskCanceledException: Task 8
//       TaskCanceledException: Task 7
//    
//    Task 2 status is now Canceled
//    Task 1 status is now RanToCompletion
//    Task 8 status is now Canceled
//    Task 7 status is now Canceled
//    Task 6 status is now RanToCompletion
//    Task 5 status is now RanToCompletion
//    Task 4 status is now RanToCompletion
//    Task 3 status is now RanToCompletion


La clase System.Threading.Tasks.Task está totalmente integrada con el modelo de cancelación basado en los tipos System.Threading.CancellationToken y System.Threading.CancellationTokenSource. Para obtener más información, vea Cancelación en subprocesos administrados y Cancelación de tareas.

Adiciones de comunidad

AGREGAR
Mostrar:
© 2014 Microsoft