Token di cancellazione in Costruttore di compiti: perché?

Alcuni costruttori System.Threading.Tasks.Task accettano un parametro CancellationToken come parametro:

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

Ciò che mi confonde è che non c’è modo di entrare nel corpo del metodo per ottenere effettivamente il token passato (ad esempio, niente come Task.CurrentTask.CancellationToken ). Il token deve essere fornito attraverso qualche altro meccanismo, come l’object stato o catturato in un lambda.

Quindi quale scopo fornisce il token di cancellazione nel costruttore?

Passando questo token nel costruttore Task lo associa a questa attività.

Citando la risposta di Stephen Toub da MSDN :

Questo ha due vantaggi principali:

  1. Se il token ha richiesto la cancellazione prima dell’avvio dell’attività, l’attività non verrà eseguita. Invece di passare a Running, passerà immediatamente a Canceled. Ciò evita i costi di esecuzione dell’attività se verrebbe annullato durante l’esecuzione.
  2. Se il corpo dell’attività monitora anche il token di cancellazione e genera un OperationCanceledException contenente quel token (che è ciò che fa ThrowIfCancellationRequested), quando l’attività vede quell’OCE, controlla se il token di OCE corrisponde al token dell’attività. In tal caso, tale eccezione viene considerata come una conferma dell’annullamento cooperativo e l’operazione passa allo stato Annullato (anziché allo stato Faultato).

Il costruttore utilizza il token per la gestione della cancellazione internamente. Se il tuo codice desidera avere accesso al token, sei responsabile del passaggio a te stesso. Consiglio vivamente di leggere la programmazione parallela con il libro di Microsoft .NET su CodePlex .

Esempio di utilizzo di CTS dal 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(); 

L’annullamento non è un caso semplice come molti potrebbero pensare. Alcune delle sottigliezze sono spiegate in questo post del blog su msdn:

Per esempio:

In alcune situazioni in Parallel Extensions e in altri sistemi, è necessario triggersre un metodo bloccato per ragioni che non sono dovute ad annullamento esplicito da parte di un utente. Ad esempio, se un thread è bloccato su blockingCollection.Take () a causa del fatto che la raccolta è vuota e un altro thread successivamente chiama blockingCollection.CompleteAdding (), la prima chiamata dovrebbe triggersrsi e generare un’eccezione InvalidOperationException per rappresentare un utilizzo errato.

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