Annullamento gettone nel costruttore Task: perché?
-
02-10-2019 - |
Domanda
Alcuni costruttori System.Threading.Tasks.Task
prendere un CancellationToken
come parametro:
CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);
Quello che mi sconcerta di questo è che non c'è modo di all'interno il corpo del metodo effettivamente arrivare al token passato a (ad esempio, niente come Task.CurrentTask.CancellationToken
). Il token Deve essere fornita attraverso qualche altro meccanismo, ad esempio l'oggetto stato o catturato in un lambda.
Quindi, quale scopo non fornire la cancellazione gettone nel costruttore servire?
Soluzione
Passando questo token nel costruttore associa compito con questo compito.
risposta di Stephen Toub da MSDN :
Questo ha due vantaggi principali:
- Se il token ha cancellazione richiesto prima della Task partenza per l'esecuzione, il task non sarà eseguito. Piuttosto che la transizione a
Running
, sarà transizione immediatamenteCanceled
. Questo evita la costi di gestione del compito, se sarebbe solo essere annullato durante l'esecuzione in ogni caso.- Se il corpo del compito è anche monitorando la cancellazione token e genera un
OperationCanceledException
contenente quella pedina (Che è quello cheThrowIfCancellationRequested
fa), poi, quando il compito vede cheOperationCanceledException
, controlla se le partite token diOperationCanceledException
della Task gettone. Se lo fa, tale eccezione è visto come un riconoscimento della cancellazione cooperativa e le transizioni compito ai annullato Stato (piuttosto che la stato di errore).
Altri suggerimenti
Il costruttore utilizza il token per gestire cancellazione internamente. Se il codice vorrebbe l'accesso al token siete responsabili per il passaggio a voi stessi. Mi raccomando la lettura del href="http://parallelpatterns.codeplex.com/" rel="noreferrer"> programmazione .
Esempio di utilizzo del 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();
cancellazione non è un semplice un caso come molti potrebbero pensare. Alcune delle sottigliezze sono spiegati in questo post del blog su MSDN:
Ad esempio:
In alcune situazioni in estensioni parallelo e in altri sistemi, è necessario svegliare un metodo bloccato per motivi non dovuti per la cancellazione esplicita da un utente. Ad esempio, se un thread è bloccato blockingCollection.Take () per la raccolta essere vuota e un altro thread chiama successivamente blockingCollection.CompleteAdding (), quindi la prima chiamata dovrebbe svegliare e lanciare un InvalidOperationException per rappresentare un errato utilizzo.
http://blogs.msdn.com /b/pfxteam/archive/2009/06/22/9791840.aspx