El blog del burgués

26 mayo 2010

Manejo de Excepciones en los hilos

Filed under: C# — elburgues @ 12:06 AM
Tags:
Consideremos el siguiente programa:
using System;
using System.Threading;

namespace Pruebas
{
    static class Program
    {
        /// <summary>
        /// El punto de entrada principal de la aplicación.
        /// </summary>
        [STAThread]
        public static void Main()
        {
            try
            {
                new Thread (Go).Start();
            }
            catch (Exception ex)
            {
                // Nosotros nunca llegaremos hasta aquí!
                Console.WriteLine ("¡Excepción!");
            }
        }

        static void Go()
        {
            throw null;
        }
    }
}
Resulta que la sentencia Try/Catch en este ejemplo no tiene ninguna utilidad y el nuevo hilo creado va a tener que cargar con una NullReferenceException. Este comportamiento adquiere sentido cuando se considera a los hilos como rutas independientes de ejecución. El remedio que se puede aplicar a esta situación es el que indica el siguiente código:
</div>
using System;
using System.Threading;

namespace Pruebas

{
    static class Program
    {
        /// <summary>
        /// El punto de entrada principal de la aplicación.
        /// </summary>
        [STAThread]
        public static void Main()
        {
            new Thread(Go).Start();
        }
        static void Go()
        {
            try
            {
                // Ésta excepción si que va a ser capturada abajo.
                throw null;
            }
            catch (Exception ex) {
                // Registrar de lo sucedido o informar a otros hilos
                // de que nos hemos vuelto inestables.
            }
        }
    }
}
>
Conclusión: Al menos en aplicaciones que estén ya en producción, un manejo explícito de excepciones debe ser incorporado en todos los métodos de entrada de todos los hilos que hayamos creado en la aplicación. Y es que desde .NET Framework 2.0 en adelante, cualquier excepción no manejada en cualquier hilo dará al traste con la aplicación entera, así que ignorar esto que te estoy contando no debería ser una opción, pero bueno, tú eliges. Además, puede ser particularmente molesto para todos aquellos programadores Windows Forms que estén acostumbrados a usar un manejador global de excepciones para toda la aplicación, como el siguiente:
using System;
using System.Windows.Forms;

namespace Pruebas
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.ThreadException +=
                new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            Application.Run(new Form1());
        }
        static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            // Éste es el manejador global de excepciones de toda la aplicación.
        }
    }
}

Las aplicaciones Windows están basadas en eventos. Eso quiere decir que actúan según mensajes que el sistema operativo manda al hilo principal de la aplicación. Estos mensajes son recibidos por la aplicación mediante llamadas repetitivas a una cola de mensajes en una sección de código llamada “Windows message loop”. Aunque las aplicaciones .NET no requieren tener acceso directo a este “Windows message loop”, automáticamente encaminan dichos eventos (como las pulsaciones de teclas, ratón…) hacia sus apropiados manejadores definidos dentro del Framework, pero en realidad, “Windows message loop” está bajo el Framework.

El evento Application.ThreadExecption se dispara cuando una excepción es lanzada desde el último código que fue llamado como resultado de un mensaje de Windows, como por ejemplo una pulsación de teclado, de ratón y más en concreto, todo el código típico de una aplicación Windows Form. Esto puede crear una falsa sensación de seguridad de que todas las excepciones que se produzcan serán capturadas por el manejador centralizado de excepciones, pero no es así. Las excepciones lanzadas dentro de otros hilos de trabajo son un buen ejemplo de excepciones que no serán capturadas por el manejador centralizado de excepciones. El código que haya dentro del método Main o el constructor del formulario principal de la aplicación son otros dos buenos ejemplos, ya que son códigos que se ejecutan antes de que “Windows message loop” arranque.

.NET Framework provee de un evento de más bajo nivel para el manejo de excepciones globales: AppDomain.UnhandledException. Este evento se dispara cuando se produce una excepción no manejada en cualquier hilo, en cualquier tipo de aplicación (con o sin interfaz de usuario). De todas formas, aunque ofrece un buen mecanismo en última instancia para atrapar excepciones no manejadas, no ofrece la posibilidad de que la aplicación no se cierre, ni de que no aparezca el cuadro de diálogo de excepción no manejada.

Anuncios

Dejar un comentario »

Aún no hay comentarios.

RSS feed for comments on this post.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Blog de WordPress.com.

A %d blogueros les gusta esto: