excepción de captura que se lanza en un hilo diferente


Uno de mis métodos (Method1) genera un nuevo hilo. Ese hilo ejecuta un método (Method2) y durante la ejecución se lanza una excepción. Necesito obtener esa información de excepción en el método de llamada(Method1)

¿Hay alguna manera de que pueda atrapar esta excepción en Method1 que se lanza en Method2?

Author: oxilumin, 2011-05-13

4 answers

En . NET 4 y superiores, puedes usar la clase Task<T> en lugar de crear un nuevo hilo. Luego puede obtener excepciones usando la propiedad .Exceptions en su objeto task. Hay 2 maneras de hacerlo:

  1. En un método separado: / / Procesas la excepción en algún subproceso de la tarea

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    
        static void ExceptionHandler(Task<int> task)
        {
            var exception = task.Exception;
            Console.WriteLine(exception);
        }
    }
    
  2. En el mismo método: / / Procesas la excepción en el hilo del llamador

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.Start();
    
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex);    
            }
    
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    }
    

Tenga en cuenta que la excepción que obtiene es AggregateException. Todo real las excepciones están disponibles a través de la propiedad ex.InnerExceptions.

En . NET 3.5 puede utilizar el siguiente código:

  1. / / Procesas la excepción en el subproceso del hijo

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
            thread.Start();            
    
            Console.ReadLine();
        }
    
        private static void Handler(Exception exception)
        {        
            Console.WriteLine(exception);
        }
    
        private static void SafeExecute(Action test, Action<Exception> handler)
        {
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                Handler(ex);
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
  2. O / / Procesas la excepción en el hilo del llamante

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
    
            thread.Start();            
    
            thread.Join();
    
            Console.WriteLine(exception);    
    
            Console.ReadLine();
        }
    
        private static void SafeExecute(Action test, out Exception exception)
        {
            exception = null;
    
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
 161
Author: oxilumin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-12 16:27:40

No se puede capturar la excepción en Method1. Sin embargo, puede capturar la excepción en Method2 y grabarla en una variable que el hilo original de ejecución pueda leer y trabajar con ella.

 8
Author: ermau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-12 20:05:48

El método más simple para compartir datos entre diferentes hilos es shared data de la siguiente manera (algunos son pseudo código):

class MyThread
{
   public string SharedData;

   public void Worker()
   {
      ...lengthy action, infinite loop, etc...
      SharedData = "whatever";
      ...lengthy action...
      return;
   }
}

class Program
{
   static void Main()
   {
      MyThread m = new MyThread();
      Thread WorkerThread = new Thread(m.Worker);
      WorkerThread.Start();

      loop//or e.g. a Timer thread
      {
         f(m.SharedData);
      }
      return;
   }
}

Puedes leer sobre este método en esta agradable introducción sobre multithreading , sin embargo, preferí leer sobre esto en el O'Reilly book C# 3.0 in a nutshell, de los hermanos Albahari (2007), que también es de libre acceso en Google Books, al igual que la versión más reciente del libro, porque también cubre la agrupación de hilos, primer plano versus hilos de fondo, etc etc, con Niza y código de ejemplo simple. (Descargo de responsabilidad: Tengo una copia desgastada de este libro)

En caso de que esté haciendo una aplicación WinForms, el uso de datos compartidos es especialmente útil, porque los controles WinForm no son seguros para subprocesos. Usando una devolución de llamada para pasar datos del subproceso worker a un control WinForm el subproceso principal de la IU necesita código feo con Invoke() para hacer que ese subproceso de control sea seguro. Usando datos compartidos en su lugar, y el subproceso único System.Windows.Forms.Timer, con un corto Interval de digamos 0.2 segundos, puede enviar fácilmente información del hilo de trabajo al control sin Invoke.

 1
Author: Roland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-03 11:58:15

Tuve un problema particular en que quería usar elementos, que contienen controles, de un conjunto de pruebas de integración, así que tengo que crear un hilo STA. El código con el que terminé es el siguiente, puesto aquí en caso de que otros tengan el mismo problema.

    public Boolean? Dance(String name) {

        // Already on an STA thread, so just go for it
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);

        // Local variable to hold the caught exception until the caller can rethrow
        Exception lException = null;

        Boolean? lResult = null;

        // A gate to hold the calling thread until the called thread is done
        var lGate = new ManualResetEvent(false);

        var lThreadStart = new ThreadStart(() => {
            try {
                lResult = DanceSTA(name);
            } catch (Exception ex) {
                lException = ex;
            }
            lGate.Set();
        });

        var lThread = new Thread(lThreadStart);
        lThread.SetApartmentState(ApartmentState.STA);
        lThread.Start();

        lGate.WaitOne();

        if (lException != null) throw lException;

        return lResult;
    }

    public Boolean? DanceSTA(String name) { ... }

Este es un pegado directo del código tal cual. Para otros usos, recomendaría proporcionar una acción o función como parámetro e invocarla en el hilo en lugar de codificar el método llamado.

 0
Author: Richard Petheram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-26 10:35:16