2010-05-13 9 views
7

Estoy repasando un libro de desarrollo general de C#, y he llegado a la sección abortar el hilo.¿Cuál es el problema con el lanzamiento oculto al capturar una ThreadAbortException?

El libro dice algo así como que cuando llamas a Thread.Abort() en otro hilo, ese hilo lanzará una ThreadAbortException, e incluso si intentas suprimirlo automáticamente lo volvería a lanzar, a menos que hayas hecho bs eso es generalmente desaprobado. Aquí está el simple ejemplo ofrecido.

using System; 
using System.Threading; 

public class EntryPoint 
{ 
    private static void ThreadFunc() 
    { 
     ulong counter = 0; 
     while (true) 
     { 
      try 
      { 
       Console.WriteLine("{0}", counter++); 
      } 
      catch (ThreadAbortException) 
      { 
       // Attempt to swallow the exception and continue. 
       Console.WriteLine("Abort!"); 
      } 
     } 
    } 

    static void Main() 
    { 
     try 
     { 
      Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc)); 
      newThread.Start(); 
      Thread.Sleep(2000); 

      // Abort the thread. 
      newThread.Abort(); 

      // Wait for thread to finish. 
      newThread.Join(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 
} 

El libro dice:

Cuando el hilo termina de procesar la excepción de aborto, el tiempo de ejecución implícita relanzamientos que al final de su manejador de excepciones. Es lo mismo que si hubieras vuelto a tirar la excepción tú mismo. Por lo tanto, cualquier manejador externo de excepciones o finalmente bloques se ejecutarán normalmente. En el ejemplo, la llamada a Join no estará esperando para siempre como se esperaba inicialmente.

Así que envolví una captura de intento alrededor de la llamada Thread.Abort() y establecí un punto de ruptura esperando que tocara esto, teniendo en cuenta que el texto dice "cualquier manejador externo de excepción o finalmente bloqueará ejecutarse normalmente". PERO NO LO HACE Estoy trabajando en mi cerebro para descubrir por qué.

¿Alguien tiene alguna idea sobre por qué este no es el caso? Es el libro mal?

Gracias de antemano.

+1

¿Qué produce su programa? –

+1

Espero que el libro también mencione que Thread.Abort es malo y nunca debería usarse. –

+0

aproximadamente 20 segundos de escribir tantos # como sea posible, luego ¡Abortar !, luego vuelve. – priehl

Respuesta

8

La excepción se produce en el hilo que se cancela. Una vez lanzada, una excepción recorre la pila de llamadas de ese hilo, pero no pasa a otro hilo, ni a la persona que llama de Thread.Abort.

La reclamación fue:

Por lo tanto, cualquier controladores de excepciones exteriores o finalmente se hace todavía se ejecutará normalmente.

una mejor prueba de esta afirmación es el siguiente código:

private static void ThreadFunc() 
{ 
    ulong counter = 0; 
    while (true) 
    { 
     try 
     { 
      try 
      { 
       Console.WriteLine("{0}", counter++); 
      } 
      catch (ThreadAbortException) 
      { 
       // Attempt to swallow the exception and continue. 
       Console.WriteLine("Abort!"); 
      } 
     } 
     catch (ThreadAbortException) 
     { 
      Console.WriteLine("Do we get here?"); 
     } 
    } 
} 

Si ThreadAbortException eran un tipo normal de excepción no podemos esperar para golpear la línea "Do we get here?", pero lo hacemos.

1

The Thread.Abort() no hace la excepción. Por el contrario, se lanza una excepción en el hilo, e incluso si lo atrapa, se vuelve a lanzar inmediatamente. En su caso, se volvería a lanzar justo después de que se imprima "Abort!". Continúa y ajusta el método del cuerpo de tu hilo en otro try/catch y podrás confirmarlo.

1

Probablemente parpadeó demasiado rápido para verlo. Modificar el código de la siguiente manera:

 // Wait for thread to finish. 
     newThread.Join(); 
     Console.ReadLine(); 

salida posible:

.... 
8807 
8808 
Abort! 
0

Al iniciar el hilo, el código sigue y el hilo que comenzó está funcionando por separado, es decir, por qué no debemos esperar golpear esa línea en main.

using System; 
using System.Threading; 

public class EntryPoint 
{ 
    private static void ThreadFunc() 
    { 
     try 
     { 
      ulong counter = 0; 
      while (true) 
      { 
       try 
       { 
        Console.WriteLine("{0}", counter++); 
       } 
       catch (ThreadAbortException) 
       { 
        // Attempt to swallow the exception and continue. 
        Console.WriteLine("Abort!"); 
       } 
      } 
     } 
     catch(ThreadAbortException) 
     { 
      Console.WriteLine("Certainly unstoppable!"); 
     } 
    } 

    static void Main() 
    { 
     try 
     { 
      Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc)); 
      newThread.Start(); 
      Thread.Sleep(2000); 

      // Abort the thread. 
      newThread.Abort(); 

      // Wait for thread to finish. 
      newThread.Join(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 
} 

Remember ThreadAbortException its a v.excepción especial, ya que para todos los propósitos el hilo está destinado a estar muerto. Eso está bien cuando estás dando por terminada tu aplicación y no tienes nada especial en el hilo. En cambio, si desea terminar con gracia las operaciones, no utilice Thread.Abort, use un mecanismo separado para indicarle al hilo que debe detenerse. Al igual que en el ejemplo, al establecer un miembro estático lo comprueba mientras tanto, el siguiente ciclo sabe que tiene que detenerse en un lugar controlado.

+0

Acepto que Thread.Abort es una manera terrible de cerrar un hilo. Habiendo dicho eso, algunas veces lo he usado cuando el hilo se niega a responder a la señal y el hilo de control se ha agotado. –

1

Lo que ese libro debería haber dijo que nunca debe usar Thread.Abort porque tiene una gran cantidad de problemas.

Como tal, cualquier comportamiento no obvio o inesperado que vea debería tomarse como una indicación de que realmente no debe usar Thread.Abort.

El objetivo de Thread.Abort es señalar a un hilo que la aplicación está terminando, que no ha salido bien (lo he preguntado), y que ahora tiene que morir. Perdón por eso, pero así son las cosas.

Eso es todo. Cualquier otro caso de uso que se te ocurra involucraría a Thread.Abort debería tener una solución diferente, punto.

Un método cooperativo suele ser la mejor manera de hacerlo. Use una señal (incluso algo tan simple como un campo booleano volátil) y simplemente configure la señal cuando desee que salga el hilo. Periódicamente, verifique esta señal en el otro subproceso, y cuando se establezca, salga. O ... incluso lanzar una excepción si detecta la señal.

Solo nunca imponen esa excepción desde el exterior usando Thread.Abort.

Ahora, una vez dicho esto, si realmente desea saber cómo manejar esta excepción, puede indicar al tiempo de ejecución que no desea que la excepción se propague automáticamente en la pila (ThreadAbortException es un caso especial) por llamando al Thread.ResetAbort().

Sin embargo, usted no debería hacer esto.

Cuestiones relacionadas