2013-04-04 5 views
9

Si consideri il codice seguente che utilizza la funzionalità della libreria di attività di base con un oggetto di CancellazioneTokenSource. Avvia un thread che riempie un dizionario con i prezzi e legge i dati da un db del server SQL. Il thread termina dopo circa 10 minuti e ogni 2 ore viene riavviato, chiamando Cancel prima nel caso in cui il thread fosse ancora in esecuzione.Eccezione durante l'esecuzione di System.Threading.Tasks.Task

private CancellationTokenSource mTokenSource = new CancellationTokenSource(); 

internal Prices(Dictionary<string, Dealer> dealers) 
{ 
    mDealers = dealers; 
    mTask = Task.Factory.StartNew 
      (() => ReadPrices(mTokenSource.Token), mTokenSource.Token); 
} 

internal void Cancel() 
{ 
    mTokenSource.Cancel(); 
} 
private void ReadPrices(CancellationToken ct) 
{ 
    using (SqlConnection connection = 
      new SqlConnection(ConfigurationManager.AppSettings["DB"])) 
    { 
     connection.Open(); 
     var dealerIds = from dealer in mDealers.Values 
         where dealer.Id != null 
         select dealer.Id; 
     foreach (var dealerId in dealerIds) 
     { 
      if (!ct.IsCancellationRequested) 
      { 
       FillPrices(connection); 
      } 
      else 
       break; 
     } 
    } 
} 

A un certo punto l'applicazione si arresta in modo anomalo con la seguente eccezione nel registro eventi.

Applicazione: Engine.exe Versione quadro: v4.0.30319 Descrizione: Il processo è stato terminato a causa di un'eccezione non gestita. Eccezione Info: System.AggregateException Stack: a System.Threading.Tasks.TaskExceptionHolder.Finalize()

Deve avere a che fare con il codice qui perché la libreria Tasks non è usato in qualsiasi altro luogo, ma non posso capire cosa c'è di sbagliato nel codice. Qualcuno ha un'idea di cosa potrebbe essere sbagliato qui?

+4

Sfortunatamente, non stai acquisendo abbastanza nel tuo registro. Un 'AggregateException' può contenere un numero qualsiasi di altre eccezioni, ed è proprio queste eccezioni che hanno maggiori probabilità di contenere informazioni utili per aiutare a diagnosticare il problema. –

+0

Inoltre "Il thread termina dopo circa 10 minuti e ogni 2 ore ... nel caso in cui il thread fosse ancora in esecuzione." - Sembra che tu stia già riflettendo su un problema che dovresti indagare - normalmente richiede 10 minuti, ma a volte funziona ancora dopo 2 ore ... –

+0

c'è un programma client che può cancellare il thread in qualsiasi momento e riavviare così la cancellazione è assolutamente necessaria – Laurijssen

risposta

19

Compiti come sentirsi ascoltati. Sembra che qualcosa non sia felice. È possibile prendere un "ultima possibilità" per ascoltare fuori, però:

TaskScheduler.UnobservedTaskException += (sender, args) => 
{ 
    foreach (var ex in args.Exception.InnerExceptions) 
    { 
     Log(ex); 
    }    
    args.SetObserved(); 
}; 

Nota questo non è inteso come l'correzione - esso è destinato a farvi vedere cosa Task sta esplodendo e con quale errore. Lo SetObserved() impedirà l'uccisione dell'applicazione. Ma la correzione qui è idealmente:

  • non lasciate che le vostre mansioni gettano,
  • o assicurarsi che siete lì per controllare lo stato del compito in seguito

E ' probabilmente non contento del rilevamento della cancellazione. IIRC il modo migliore per farlo sarebbe:

foreach(...) { 
    if(ct.IsCancellationRequested) { 
     // any cleanup etc 
     ct.ThrowIfCancellationRequested(); 
    } 
    ... 
} 

o più semplicemente, se non è necessaria alcuna pulizia, basta:

foreach(...) { 
    ct.ThrowIfCancellationRequested(); 
    ... 
} 

Allo stesso modo, potrebbe essere solo un'eccezione accesso ai dati. Ci sono qualsiasi numero di eccezioni che possono accadere quando si parla con un database. Timeout, deadlock, impossibile connettersi, ecc.