2009-04-22 13 views
13

Tengo una idea de por qué, pero me gustaría preguntar si alguien tiene una buena idea de por qué la excepción que se genera dentro de un hilo nunca es atrapada por el código que la inició. Aquí hay un código muy simple para demostrar lo que quiero decir: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); 
      } 
     } 
    } 
} 

ingenuamente pensé que al tener el try/catch estaría a salvo, pero me pareció que el camino difícil que no es el caso (es estrellarse uno de mis servicios).

+0

Extraño, estaba a punto de comenzar un hilo similar en este momento. –

+0

Estoy seguro de que las Excepciones brillaron hasta el hilo de llamada. Aunque no estoy usando ThreadPool. solo Subproceso T = subproceso nuevo (nuevo ThreadStart (delegado() {Console.WriteLine ("Crash!"); DoCrashyThingy();})); T.Start(); – Fusspawn

+0

Podría fácilmente estar equivocado al respecto, la mayor parte de mi trabajo es este horrible gigante de un solo hilo .. – Fusspawn

Respuesta

28

Bueno, en general, no tienes idea de dónde estará el hilo de origen cuando se lanza la excepción en el nuevo hilo. ¿Por qué esperaría el hilo para lanzar una excepción?

Piensa en las pilas involucradas: cuando se lanza una excepción, sube la pila hasta que alcanza un bloque catch apropiado. El nuevo hilo tiene una pila completamente separada para el hilo de creación, por lo que nunca llegará al bloque catch en la pila del hilo de creación.

EDITAR: Por supuesto, podría diseñar su sistema para que el hilo de creación hiciera esperar a que ocurrieran otras cosas, un poco como el ciclo de mensajes en una aplicación de Windows Forms. El nuevo hilo podría atrapar la excepción y enviar un mensaje al hilo de creación, que luego podría tratar con la excepción. Sin embargo, esa no es la configuración normal, tienes que hacerlo todo explícitamente.

+0

Gracias, Jon. Lo que me desconcertó fue que realmente bloquea el proceso principal; Me imagino que el hilo debería al menos morir pacíficamente en lugar de derribar todo con él. –

+0

No, el punto es que una excepción inesperada puede indicar que algo está muy mal y, en general, fracasar rápido es una mejor idea. Este es un nuevo comportamiento a partir de .NET 2.0. Ver http://msdn.microsoft.com/en-us/library/ms228965.aspx –

+0

Así que concluiría que cualquier bloque de código que está en cola en una cola de hilos debe estar totalmente encerrado en un bloque try/catch en sí mismo, sería eso ser una mejor practica?Tengo un servicio que no me gustaría que baje solo porque uno de sus hilos se metió en problemas ... –

2

Es una mala idea hacer suposiciones, especialmente cuando se trata de varios hilos (ya sabes el dicho anterior).

¿Por qué sería el código que inició el hilo de la excepción? El código que inició el subproceso puede no existir incluso cuando se lanza la excepción.

+1

como un lado, odio ese dicho porque ignora la realidad de que necesitamos suposiciones para sobrevivir. El dicho debe referirse a la comprensión de cuáles son sus suposiciones y a determinar dónde son incorrectas. –

2

El hilo en ejecución no quedará atrapado en su instrucción try/catch porque se está ejecutando en otro hilo. Try/Catch solo funciona para el hilo actual. Lo que debe hacer es intentar/capturar la función que ejecuta el subproceso y tener alguna forma de gestionar lo que sucede cuando se produce el bloqueo.

2

Es posible que desee utilizar un EventGeneratingThread wrapper - esto le permitirá detectar y lidiar con las excepciones lanzadas en los hilos del proceso que los engendró.

2

Trate de añadir esto antes de su DoWork Sub

<System.Diagnostics.DebuggerNonUserCodeAttribute()> _ 

estoy usando el trabajador fondo, y todo el intento de captura en mi trabajo de bucle como era de esperar que con este.