.net - ¿Cómo manejar todas las excepciones no controladas al usar Task Parallel Library?
multithreading .net-4.0 (3)
Creo que TaskScheduler.UnobservedTaskException Event es lo que quieres:
Se produce cuando una excepción no observada de una tarea en quiebra está a punto de desencadenar una política de escalación de excepciones, que, de forma predeterminada, daría por terminado el proceso.
Por lo tanto, este evento es similar a DomainUnhandledException
que mencionó en su pregunta, pero se produce solo para las tareas.
Por cierto, esa política de excepción no observada (sí, esto no es una excepción no observada, los chicos de MS inventaron una nueva palabra ... otra vez), cambió de .NET 4.0 a .NET 4.5. En .NET 4.0 excepción no observada lleva a la terminación del proceso, pero en .NET 4.5 - no. Todo esto se debe a las nuevas cosas asincrónicas que tendremos en C # 5 y VB 11.
Estoy usando TPL ( Task Parallel Library ) en .NET 4.0. Quiero ser capaz de centralizar la lógica de manejo de todas las excepciones no controladas mediante el uso del Thread.GetDomain().UnhandledException
. Sin embargo, en mi aplicación, el evento nunca se Task.Factory.StartNew(...)
para los hilos iniciados con el código TPL, por ejemplo Task.Factory.StartNew(...)
. El evento se dispara si uso algo como new Thread(threadStart).Start()
.
Este artículo de MSDN sugiere utilizar Task # Wait () para capturar la AggregateException
cuando se trabaja con TPL, pero eso no es lo que quiero porque no es un mecanismo "centralizado".
¿Alguien tiene el mismo problema o solo soy yo? ¿Tienes alguna solución para esto?
Parece que no hay una forma integrada de manejar esto (y no hay respuesta a esta pregunta después de casi 2 semanas). Ya saqué un código personalizado para encargarme de esto. La descripción de la solución es bastante larga, así que la publiqué en mi blog. Consulte esta publicación si le interesa.
Actualización 5/7/2010: He encontrado una mejor manera de hacerlo, haciendo uso de la continuación de tareas. Creo una class ThreadFactory
que expone el evento de error que puede ser suscrito por un controlador de nivel superior y proporciona métodos para iniciar una tarea adjunta con la continuación adecuada.
El código está publicado aquí .
Actualización 18/04/2011: Código postal de la publicación del blog según el comentario de Nifle.
internal class ThreadFactory
{
public delegate void TaskError(Task task, Exception error);
public static readonly ThreadFactory Instance = new ThreadFactory();
private ThreadFactory() {}
public event TaskError Error;
public void InvokeError(Task task, Exception error)
{
TaskError handler = Error;
if (handler != null) handler(task, error);
}
public void Start(Action action)
{
var task = new Task(action);
Start(task);
}
public void Start(Action action, TaskCreationOptions options)
{
var task = new Task(action, options);
Start(task);
}
private void Start(Task task)
{
task.ContinueWith(t => InvokeError(t, t.Exception.InnerException),
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
task.Start();
}
}
Veo dos opciones que se pueden usar para fines de centralización del manejo de excepciones en TPL: 1. Uso del evento de excepción de tarea no observada del Programador de tareas. 2. Uso de continuaciones para tareas con estado en falla.
Uso del evento de excepción de tarea no observada del Programador de tareas.
El planificador de tareas tiene un evento UnobservedTaskException al que puede suscribirse utilizando operator + =.
- Nota 1: en el cuerpo del controlador, debe hacer que la llamada SetObserved () en el argumento UnobservedTaskExceptionEventArgs notifique al planificador que se manejó la excepción.
- Nota 2: se llama al controlador cuando el recolector de basura ha recopilado las tareas.
- Nota 3: si espera en la tarea, se verá obligado a proteger la espera mediante el bloqueo de prueba / captura.
- Nota 4: La política predeterminada para excepciones de tareas no controladas en .Net 4.0 y 4.5 es diferente.
Resumen: este enfoque es útil para tareas de "olvidar y olvidar" y para detectar excepciones que escaparon de su política centralizada de manejo de excepciones.
Uso de continuaciones para tareas con estado en falla.
Con TPL puede adjuntar acciones a la tarea mediante el método ContinueWith () que toma la acción de adjuntar y la opción de continuación. Se llamará a esta acción después de la terminación de la tarea y solo en los casos especificados por opción. En particular:
t.ContinueWith(c => { /* exception handling code */ }, TaskContinuationOptions.OnlyOnFaulted);
instala la continuación con el código de manejo de excepciones en la Tarea t. Este código se ejecutará solo en el caso cuando finalizó la Tarea t debido a la excepción no controlada.
- Nota 1: Obtenga un valor de excepción en el código de manejo de excepciones. De lo contrario, se borrará.
- Nota 2: se llamará al código de manejo de excepciones inmediatamente después de la terminación de la tarea.
- Nota 3: Si la excepción se obtuvo en el código de manejo de excepciones, se considerará como manejada, el bloque try / catch en la tarea no podrá detectarlo.
Creo que será mejor para el manejo de excepciones centralizado usar Tareas personalizadas heredadas de Tarea con el controlador de excepción agregado a través de la continuación. Y acompañe este enfoque utilizando el evento Excepción de tarea no observada del Programador de tareas para detectar intentos de utilizar tareas no personalizadas.