captura de excepción que se lanza en un hilo diferente
109
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 forma en que pueda detectar esta excepción en la Method1que se incluye Method2?
En .NET 4 y superior, puede usar la Task<T>clase en lugar de crear un nuevo hilo. Entonces puede obtener excepciones usando la .Exceptionspropiedad en su objeto de tarea. Hay 2 formas de hacerlo:
En un método separado: // Procesas la excepción en el hilo de alguna tarea
Tenga en cuenta que la excepción que obtiene es AggregateException. Todas las excepciones reales están disponibles a través de la ex.InnerExceptionspropiedad.
Lo siento, pero olvidé mencionar que estoy usando .NET 3.5. Según mi entendimiento, ¿la tarea es 4.0?
Estudiante de Silverlight
2
@SilverlightStudent Ok, acabo de actualizar mi respuesta para satisfacer sus requisitos.
oxilumin
@oxilumin: Gracias y muy apreciado. Una pregunta de seguimiento más. Si su método Test () también toma algunos argumentos, ¿cómo modificará el método SafeExecute para esos argumentos?
Estudiante de Silverlight
2
@SilverlightStudent En este caso, pasaré una lambda en lugar de Test. Me gusta() => Test(myParameter1, myParameter2)
oxilumin
2
@SilverlightStudent: actualizado.
oxilumin
9
No puede detectar la excepción en Method1. Sin embargo, puede capturar la excepción en Method2 y registrarla en una variable que el hilo de ejecución original pueda leer y trabajar con ella.
Gracias por su respuesta. Entonces, si Method1 es parte de Class1 y tengo una variable de tipo Exception en esa clase. Siempre que Method2 lanza una excepción, también establece esa variable de excepción en Class1. ¿Suena como un diseño justo? ¿Existen formas de mejores prácticas para manejar este escenario?
Estudiante de Silverlight
Correcto, simplemente almacena la excepción y accede a ella más tarde. No es raro que los métodos que se ejecuten en el futuro (especialmente las devoluciones de llamada para cuando el Método2 esté completo) luego vuelvan a generar esa excepción como si ellos mismos la hubieran causado, pero esto realmente depende de lo que desee.
ermau
0
El método más simple para compartir datos entre diferentes hilos es el shared datasiguiente (algunos son pseudocódigo):
classMyThread{publicstringSharedData;publicvoidWorker(){...lengthy action, infinite loop, etc...SharedData="whatever";...lengthy action...return;}}classProgram{staticvoidMain(){MyThread m =newMyThread();ThreadWorkerThread=newThread(m.Worker);WorkerThread.Start();
loop//or e.g. a Timer thread{
f(m.SharedData);}return;}}
Puedes leer sobre este método en esta bonita introducción sobre el multihilo , 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 subprocesos, subprocesos en primer plano frente a subprocesos en segundo plano, etc., con un código de ejemplo agradable y simple. (Descargo de responsabilidad: tengo una copia gastada de este libro)
En caso de que esté creando una aplicación WinForms, el uso de datos compartidos es especialmente útil, porque los controles de WinForm no son seguros para subprocesos. Al usar una devolución de llamada para pasar datos del hilo de trabajo a un control de WinForm, el hilo de la interfaz de usuario principal necesita un código desagradable Invoke()para que ese control sea seguro para los hilos. En su lugar, utilizando datos compartidos y el subproceso único System.Windows.Forms.Timer, con menos Intervalde 0,2 segundos, puede enviar fácilmente información desde el subproceso de trabajo al control sin él Invoke.
Tuve un problema particular porque quería usar elementos, que contenían 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.
publicBoolean?Dance(String name){// Already on an STA thread, so just go for itif(Thread.CurrentThread.GetApartmentState()==ApartmentState.STA)returnDanceSTA(name);// Local variable to hold the caught exception until the caller can rethrowException lException =null;Boolean? lResult =null;// A gate to hold the calling thread until the called thread is donevar lGate =newManualResetEvent(false);var lThreadStart =newThreadStart(()=>{try{
lResult =DanceSTA(name);}catch(Exception ex){
lException = ex;}
lGate.Set();});var lThread =newThread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();if(lException !=null)throw lException;return lResult;}publicBoolean?DanceSTA(String name){...}
Se trata de 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.
Test
. Me gusta() => Test(myParameter1, myParameter2)
No puede detectar la excepción en Method1. Sin embargo, puede capturar la excepción en Method2 y registrarla en una variable que el hilo de ejecución original pueda leer y trabajar con ella.
fuente
El método más simple para compartir datos entre diferentes hilos es el
shared data
siguiente (algunos son pseudocódigo):Puedes leer sobre este método en esta bonita introducción sobre el multihilo , 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 subprocesos, subprocesos en primer plano frente a subprocesos en segundo plano, etc., con un código de ejemplo agradable y simple. (Descargo de responsabilidad: tengo una copia gastada de este libro)En caso de que esté creando una aplicación WinForms, el uso de datos compartidos es especialmente útil, porque los controles de WinForm no son seguros para subprocesos. Al usar una devolución de llamada para pasar datos del hilo de trabajo a un control de WinForm, el hilo de la interfaz de usuario principal necesita un código desagradable
Invoke()
para que ese control sea seguro para los hilos. En su lugar, utilizando datos compartidos y el subproceso únicoSystem.Windows.Forms.Timer
, con menosInterval
de 0,2 segundos, puede enviar fácilmente información desde el subproceso de trabajo al control sin élInvoke
.fuente
Tuve un problema particular porque quería usar elementos, que contenían 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.
Se trata de 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.
fuente