Token de cancelación en el constructor de tareas: ¿por qué?

Ciertos constructores System.Threading.Tasks.Task toman un CancellationToken como parámetro:

 CancellationTokenSource source = new CancellationTokenSource(); Task t = new Task (/* method */, source.Token); 

Lo que me desconcierta acerca de esto es que no hay forma de que dentro del cuerpo del método llegue realmente al token pasado (por ejemplo, nada como Task.CurrentTask.CancellationToken ). El token debe proporcionarse a través de algún otro mecanismo, como el objeto de estado o capturado en un lambda.

Entonces, ¿para qué sirve servir el token de cancelación en el constructor?

Pasar este token al constructor de tareas lo asocia con esta tarea.

Citando la respuesta de Stephen Toub de MSDN :

Esto tiene dos beneficios principales:

  1. Si el token tiene una cancelación solicitada antes de que la Tarea comience a ejecutarse, la Tarea no se ejecutará. En lugar de hacer la transición a Running, pasará inmediatamente a Canceled. Esto evita los costos de ejecutar la tarea si simplemente se cancela mientras se ejecuta de todos modos.
  2. Si el cuerpo de la tarea también está supervisando el token de cancelación y arroja una OperationCanceledException que contiene ese token (que es lo que hace ThrowIfCancellationRequested), cuando la tarea ve ese OCE, comprueba si el token del OCE coincide con el token de Task. Si lo hace, esa excepción se considera como un acuse de recibo de cancelación cooperativa y la Tarea pasa al estado Cancelado (en lugar del estado Fallo).

El constructor utiliza el token para el manejo de la cancelación internamente. Si su código desea acceder al token, usted es responsable de pasárselo. Recomiendo leer la progtwigción paralela con el libro de Microsoft .NET en CodePlex .

Ejemplo de uso de CTS del libro:

 CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; Task myTask = Task.Factory.StartNew(() => { for (...) { token.ThrowIfCancellationRequested(); // Body of for loop. } }, token); // ... elsewhere ... cts.Cancel(); 

La cancelación no es un simple caso, como muchos podrían pensar. Algunas de las sutilezas se explican en esta publicación de blog en msdn:

Por ejemplo:

En ciertas situaciones en Extensiones paralelas y en otros sistemas, es necesario activar un método bloqueado por razones que no se deben a la cancelación explícita de un usuario. Por ejemplo, si un hilo está bloqueado en blockingCollection.Take () debido a que la colección está vacía y otro hilo posteriormente llama a blockingCollection.CompleteAdding (), entonces la primera llamada se debe activar y arrojar una InvalidOperationException para representar un uso incorrecto.

http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx