2012-01-08 18 views
8

Estoy familiarizado con el hecho de que la excepción lanzada en un hilo normalmente no puede quedar atrapada en otro hilo. ¿Cómo puedo transferir el error al hilo principal?Cómo pasar una excepción explícitamente al hilo principal en C#

public static void Main() 
{ 
    new Thread (Go).Start(); 
} 

static void Go() 
{ 
    try 
    { 
    // ... 
    throw null; // The NullReferenceException will get caught below 
    // ... 
    } 
    catch (Exception ex) 
    { 
    // Typically log the exception, and/or signal another thread 
    // that we've come unstuck 
    // ... 
    } 
} 

Respuesta

6

Si está utilizando .NET 4 hay mejores maneras de hacer esto con Tasks, pero asumiendo que es necesario utilizar Threads ...

Si el ejemplo es una aplicación de consola, a continuación, su método principal saldrá , posiblemente antes de que Go comience a ejecutarse. Por lo tanto, su "hilo principal" puede no existir cuando se lanza la excepción. Para detener esto, necesitas algo de sincronización.

Algo como esto debería hacer:

static Exception _ThreadException = null; 

public static void Main() 
{ 
    var t = new Thread (Go); 
    t.Start(); 

    // this blocks this thread until the worker thread completes 
    t.Join(); 

    // now see if there was an exception 
    if (_ThreadException != null) HandleException(_ThreadException); 
} 

static void HandleException(Exception ex) 
{ 
    // this will be run on the main thread 
} 

static void Go() 
{ 
    try 
    { 
     // ... 
     throw null; // The NullReferenceException will get caught below 
     // ... 
    } 
    catch (Exception ex) 
    { 
     _ThreadException = ex; 
    } 
} 

Si se trata de una aplicación de interfaz de usuario, las cosas son un poco más fácil. Deberá pasar alguna referencia a su subproceso de interfaz de usuario en el método Go para que sepa dónde enviar la excepción. La mejor manera de hacerlo es pasar el SynchronizationContext del subproceso UI.

Algo como esto funcionaría:

public static void Main() 
{ 
    var ui = SynchronizationContext.Current; 
    new Thread (() => Go(ui)).Start(); 
} 

static void HandleException(Exception ex) 
{ 
    // this will be run on the UI thread 
} 

static void Go(SynchronizationContext ui) 
{ 
    try 
    { 
     // ... 
     throw null; // The NullReferenceException will get caught below 
     // ... 
    } 
    catch (Exception ex) 
    { 
     ui.Send(state => HandleException(ex), null); 
    } 
} 
7

Si C# 4.0 está disponible para usted, entonces usted puede utilizar un Task en lugar de un Thread. Las excepciones no detectadas en el Task se propagan automáticamente al hilo de unión. Vea aquí: http://msdn.microsoft.com/en-us/library/dd997415.aspx para ejemplos y excepciones a esta regla.

+0

C# 4.0 no está disponible – user829174

0

Supongo que su llamado "hilo principal" debe sondear o esperar excepciones. Esto se puede hacer con una cola y un semáforo.

catch(Exception ex) 
{ 
    lock(queueLock) 
    { 
     queue.Enqueue(ex) 
     semaphore.Release(); 
    } 

} 

En su hilo principal puede sondear o esperar al semáforo.

2

Este es un hilo muy viejo, pero tengo un enfoque original para este problema, así que voy a poner mi solución aquí.

El objetivo principal en mi caso fue que el hilo principal se interrumpirá por excepción en el momento en que el hilo hijo recibió la excepción, en lugar de monitorear o esperar como se propone en otras respuestas. Como se ha dicho en otros hilos, no podemos hacer eso de forma convencional, pero podemos enviar interrupciones desde el otro hilo al hilo principal.

El envío de interrupción al hilo principal genera ThreadInterruptedException en el hilo principal. Así que atraparlo en el hilo principal y verificar cualquier indicador levantado por el otro hilo hará que los detalles de la excepción se transfieran también.

Aquí está un ejemplo mínimo (se puede romper a clases y hacer un mejor diseño más adelante)

static void Main(string[] args) 
    { 


     // initialize the second thread *************************** 
     Exception exFromThread = null; 

     Thread thread = new Thread((mainThread) => 
     { 
      Thread.Sleep(1000); 
      exFromThread = new Exception("Exception from other thread"); 
      ((Thread)mainThread).Interrupt(); // makes the main thread get exception 
     }); 

     thread.Start(Thread.CurrentThread); 
     // ******************************************************** 

     try 
     { 
      // This loop represents your main thread logic 
      for (int i = 0; true; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("main thread logic: " + i); 
      } 
     } 
     catch (ThreadInterruptedException ex) 
     { 
      Console.WriteLine("Thread have been interrupted"); 
      Console.WriteLine(exFromThread.Message); 
     } 

     Console.WriteLine("Press any key.."); 

     Console.ReadLine(); 
    } 
Cuestiones relacionadas