2012-05-12 14 views
7

Ho la seguente configurazione nel mio codice che utilizza il TPL:TPL cancellazione continuazione mai invitato annullato Task

  • Un campo nella mia classe: private CancellationTokenSource _cancellationTokenSource;
  • Questo CancellationTokeSource viene instatiated ogni volta che creo un compito TPL che utilizza quel particolare CancellationToken

I compiti TPL actualy simile a questa:

var dataRetrievalTask = new Task<List<myType>>(() => 
      { 
       // retrieve data and do something 
       foreach (var a in retrievalMethod()) 
       { 
        if (_cancellationTokenSource.Token.IsCancellationRequested) 
         _cancellationTokenSource.Token.ThrowIfCancellationRequested(); 

         // do something if not cancelled 
        } 
       } 

       return filledListOfMyType; 

      }, _cancellationTokenSource.Token); 

      // define what shall happen if data retrievel finished without any problems 
      var writingLoadedDataToGridTask = dataRetrievalTask.ContinueWith(task => 
      { 
       // do something in case we ran to completion without error 
      }, _cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, currentScheduler); 

      // what to do in case cancellation was performed 
      var loadingDataCancelledTask = dataRetrievalTask.ContinueWith(task => 
           { 
           someLabel.Text = "Data retrieval canceled."; 
           },_cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnCanceled, currentScheduler); 

      // what to do in case an exception/error occured 
      var loadingDataFaulted = dataRetrievalTask.ContinueWith(task => 
       { 
        someLabel.Text = string.Format("Data retrieval ended with an Error."); 
       }, _cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnFaulted, currentScheduler); 

      // when any of the continuation tasks ran through, reset ui controls/buttons etc 
      Task.Factory.ContinueWhenAny(new[] { writingLoadedDataToGridTask, loadingDataCancelledTask, loadingDataFaulted }, task => 
      { 
       // reset controls and all that 
      }, _cancellationTokenSource.Token, TaskContinuationOptions.None, currentScheduler); 


      dataRetrievalTask.Start(); 

Ora il mio problema è che quando il _cancellationTokenSource.Cancel Il metodo() viene chiamato da qualche parte (nel gestore di eventi .Click del pulsante Annulla) che il particolare corpo/metodo loadingDataCancelledTask non viene chiamato.

Cosa sto facendo di sbagliato qui? Sto usando e consegnando la stessa istanza _cancellationTokenSource.Token ... e tutto il resto (le attività 'writeLoadedDataToGridTask' e 'loadingDataFaulted' & il seguente 'Task.Factory.ContinueWhenAny (new [] {writingLoadedDataToGridTask, loadingDataCancelledTask, loadingDataFaulted}, task => ...' blocco) non funzionano davvero. Solo la cancellazione non è così. qualcuno vedere/sapere perché?

risposta

8

tuo continuazione cancellazione viene annullata perché utilizza lo stesso motivo di annullamento.

Se ci pensate ha perfettamente senso: quando dici "Voglio annullare l'elaborazione" ottieni effettivamente ciò che chiedi. Tutto il processo si interrompe, compreso l'aggiornamento dell'interfaccia utente.

La soluzione è di non utilizzare il token di cancellazione per la cancellazione, l'errore e le continuazioni ContinueWhenAny. In questo modo queste continuazioni funzionano sempre.

+1

oh mio, ora che lo dici .. ha senso, sì. Molte grazie!! –

+0

Quindi cosa significa "TaskContinuationOptions.OnlyOnCanceled"? Non funzionerà mai? – Jasper

+0

Significa che viene eseguito quando l'attività * di base * viene annullata. Ma puoi anche annullare la continuazione. Se non vuoi che questo non passi un token di cancellazione ad esso. – usr

Problemi correlati