2009-10-12 18 views
8

Recientemente he asistido a una entrevista. Me da un fragmento de código. Lo sé, el entrevistador lo tomó de la muestra de enhebrado de albhari.Manejo de excepciones en hilos

public static void Main() 
{ 
    try 
    { 
     new Thread (Go).Start(); 
    } 
    catch (Exception ex) 
    { 
     // We'll never get here! 
     Console.WriteLine ("Exception!"); 
    } 
} 

static void Go() { throw null; } 

La modificación del código anterior como

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

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

sería el buen candidato para manejar la excepción.

me han preguntado: "Si la pista por encima de lo que son las otras alternativas serían encajan tan buena solución ?. Era difícil encontrar la alternativa, por lo que plantean aquí para recoger su sugerencia.

Respuesta

15

excepción lanzada en un hilo que normalmente no podrían ser capturados en otro hilo.

será mejor para cogerlo en la función y pasa a hilo principal de forma explícita.

sin embargo, si lo que desea es registrar todos los mensajes no controladas de todos los hilos, puede usar el evento AppDomain.UnhandledException o eventos equivalentes en la clase de Aplicación si es desarrollando WinForms o la aplicación WPF.

+10

... pero tenga en cuenta que no se puede controlar la excepción de AppDomain.UnhandledException, te notificarán pero la aplicación dejará de estar de todos modos . – Lucero

+1

Es posible evitar que la aplicación se detenga estableciendo el modo de compatibilidad v1.x. Para esto, se debe agregar un elemento a app.config en la

3

¿cuáles son las otras alternativas encajarían como buena solución ?.

Solución a qué? ¿Qué problema estás tratando de resolver?

Si utiliza BackgroundWorker, en lugar de hilo, que tiene un evento RunWorkerCompleted, y dentro de ella se puede comprobar el parámetro RunWorkerCompletedEventArgs para la propiedad de error. Esto generalmente se usa en aplicaciones WinForms o WPF, porque hay un buen soporte para BackgroundWorker en el diseñador de Visual Studio.

También podría definir un delegado para Go() y llamar a BeginInvoke() en él. Por supuesto, también necesita EndInvoke().

Además, generalmente no es una buena idea iniciar subprocesos aleatorios. Los delegados ThreadPool.QueueUserWorkItem, BackgroundWorker o asynch utilizan el ThreadPool y se recomiendan.

+0

al mismo código que pidieron alternativas. – user184805

+0

bueno, lo que quiero decir es esto: el código original estaba roto. Tu primera opción es una alternativa. SI es satisfactorio, entonces no necesita otras alternativas. ¿Que problema estas tratando de resolver? "una alternativa al código original" podría ser * cualquier cosa *. Podrías enviar un código que resuelva los rompecabezas de sudoku, eso sería una alternativa. ¿Sería apropiado? Sin requisitos, ¿quién puede decir? – Cheeso

+0

No señor, el entrevistador hizo esa pregunta. :) así que no dije nada. Además, no sabía cómo abordarlo. :) Gracias por tu sugerencia. – user184805

0

hay alternativas que figuran en el sitio web de Joe Albahari: http://www.albahari.com/threading/#_Exception_Handling

"Hay, sin embargo, algunos casos en los que no es necesario para manejar excepciones en un subproceso de trabajo, debido a que el .NET Framework lo hace por usted .Estos se tratan en las secciones siguientes, y son:
delegados -Asynchronous
-BackgroundWorker
-La tarea paralela Biblioteca (condiciones)"

0

Creo que esta es la manera más fácil es:

BackgroundWorker bw = new BackgroundWorker(); 
bw.DoWork += new DoWorkEventHandler((object sender2, DoWorkEventArgs e2) => 
{ 
    throw new Exception("something bad"); 
    e2.Result = 1 + 1; 
}); 
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((object sender2, RunWorkerCompletedEventArgs e2) => 
{ 
    if (e2.Error != null) 
    { 
     Console.WriteLine("Error: " + e2.Error.Message); 
    } 
}); 
bw.RunWorkerAsync(); 

pero hay otra manera que algunos prefieren si quieres sincronizar el hilo (quizás esto esté en un hilo que no sea el hilo de la interfaz gráfica de usuario):

private class FileCopier 
    { 
     public bool failed = false; 
     public Exception ex = null; 
     public string localPath; 
     public string dstPath; 
     public FileCopier(string localPath, string dstPath) 
     { 
      this.localPath = localPath; 
      this.dstPath = dstPath; 
     } 

     public void Copy() 
     { 
      try{ 
       throw new Exception("bad path"); 
      }catch(Exception ex2) 
      { 
       ex = ex2; 
       failed = true; 
      } 
     } 
    } 

    public static void Main() 
    { 
     FileCopier fc = new FileCopier("some path", "some path"); 
     Thread t = new Thread(fc.Copy); 
     t.Start(); 
     t.Join(); 
     if (fc.failed) 
      Console.WriteLine(fc.ex.Message); 
    } 

Tenga en cuenta que el segundo ejemplo tendría más sentido si tiene varios hilos, los recorre y los une ... pero mantuve el ejemplo simple.

la tercera patrón sería el uso de tareas fábrica que es más limpio:

private static test(){ 
    List<Task<float>> tasks = new List<Task<float>>(); 
    for (float i = -3.0f; i <= 3.0f; i+=1.0f) 
    { 
     float num = i; 
     Console.WriteLine("sent " + i); 
     Task<float> task = Task.Factory.StartNew<float>(() => Div(5.0f, num)); 
     tasks.Add(task); 
    } 

    foreach(Task<float> t in tasks) 
    { 
     try 
     { 
      t.Wait(); 
      if (t.IsFaulted) 
      { 
       Console.WriteLine("Something went wrong: " + t.Exception.Message); 
      } 
      else 
      { 
       Console.WriteLine("result: " + t.Result); 
      } 
     }catch(Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
     } 

    } 
} 

private static float Div(float a, float b) 
{ 
    Console.WriteLine("got " + b); 
    if (b == 0) throw new Exception("Divide by zero"); 
    return a/b; 
}