2009-04-22 17 views
13

Ho un'idea del perché, ma mi piacerebbe chiedere se qualcuno ha una buona comprensione del motivo per cui l'eccezione sollevata all'interno di un thread non viene mai catturata dal codice che l'ha avviato. Ecco qualche codice molto semplice per dimostrare quello che voglio dire:Try/Catch and threading

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace TestCrash 
{ 
    class Program 
    { 
     private static void Crash(object control) 
     { 
      AutoResetEvent are = (AutoResetEvent)(((object[])control)[0]); 
      are.Set(); 
      throw new Exception("Burn baby burn"); 
     } 
     static void Main(string[] args) 
     { 
      try 
      { 
       List<WaitHandle> waitHandles = new List<WaitHandle>(); 
       for (int i = 0; i < 100; i++) 
       { 
        AutoResetEvent are = new AutoResetEvent(false); 
        waitHandles.Add(are); 
        object[] procControl = new object[] { are }; 
        ThreadPool.QueueUserWorkItem(Crash, procControl); 
        WaitHandle.WaitAll(waitHandles.ToArray()); 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
      } 
     } 
    } 
} 

ho ingenuamente pensato che avendo il try/catch vorrei essere al sicuro, ma ho trovato il modo rigido che non è il caso (è crash uno dei miei servizi).

+0

Strano, stavo per iniziare un thread simile proprio ora. –

+0

Sono sicuro che le Eccezioni hanno avuto bolle sul thread chiamante. Altrimenti non sto usando ThreadPool. solo Thread T = new Thread (new ThreadStart (delegate() {Console.WriteLine ("Crash!"); DoCrashyThingy();})); T.Start(); – Fusspawn

+0

Potrei facilmente sbagliarmi, la maggior parte del mio lavoro è questo orribile single threaded behemoth .. – Fusspawn

risposta

28

In generale, non si ha idea di dove sarà il thread di origine nel momento in cui viene generata l'eccezione nel nuovo thread: perché attendere il thread per generare un'eccezione?

Pensa agli stack coinvolti: quando un'eccezione viene lanciata, salta allo stack fino a raggiungere un blocco catch appropriato. Il nuovo thread ha uno stack completamente separato per il thread di creazione, quindi non raggiungerà mai il blocco catch nello stack del thread di creazione.

EDIT: Naturalmente, si potrebbe progettare il sistema in modo che il filo creazione fatto attesa per altre cose accadano - un po 'come il ciclo di messaggi in un'applicazione Windows Form. Il nuovo thread potrebbe quindi rilevare l'eccezione e inviare un messaggio al thread di creazione, che potrebbe quindi gestire l'eccezione. Questa però non è la configurazione normale - devi fare tutto in modo esplicito.

+0

Grazie, Jon. Ciò che mi ha lasciato perplesso è che in realtà blocca il processo genitore; Immagino che il thread dovrebbe almeno morire pacificamente invece di portare tutto giù con esso. –

+0

No: il punto è che un'eccezione inaspettata può ben indicare che qualcosa è seriamente sbagliato, e il non riuscire veloce è generalmente un'idea migliore. Questo è un nuovo comportamento da .NET 2.0. Vedere http://msdn.microsoft.com/en-us/library/ms228965.aspx –

+0

Quindi vorrei concludere che qualsiasi blocco di codice che viene accodato in una coda di thread deve essere completamente racchiuso in un blocco try/catch stesso, sarebbe quello essere una buona pratica?Ho un servizio che non vorrei scendere solo perché uno dei suoi thread si è messo nei guai ... –

2

È una cattiva idea fare supposizioni, specialmente dove sono coinvolti più thread (si conosce quel vecchio detto).

Perché il codice che ha avviato il thread vede l'eccezione? Il codice che ha avviato il thread potrebbe non esistere nemmeno quando viene generata l'eccezione.

+1

come una parte, odio questo detto perché ignora la realtà che richiediamo supposizioni per sopravvivere. Il detto dovrebbe riferirsi a capire quali sono le vostre ipotesi e determinare dove sono errate. –

2

Il thread in esecuzione non verrà rilevato nell'istruzione try/catch perché è in esecuzione in un altro thread. Try/Catch funziona solo per il thread corrente. Quello che devi fare è provare/catturare la funzione che viene eseguita dal thread e avere un modo per gestire cosa succede quando si verifica il crash.

2

Si potrebbe voler utilizzare un EventGeneratingThread wrapper - questo vi permetterà di catturare e gestire le eccezioni generate nelle discussioni dal processo che le ha generate.

2

Prova ad aggiungere questa prima DoWork Sub

<System.Diagnostics.DebuggerNonUserCodeAttribute()> _ 

sto usando il lavoratore sfondo, e tutto il tentativo di cattura nel mio lavoro ciclo come li aspetterebbe a questo.