Как обрабатывать все необработанные исключения при использовании задач параллельной библиотеки?

StackOverflow https://stackoverflow.com/questions/2707295

Вопрос

Я использую TPL (Задача параллельной библиотеки) в .NET 4.0. Я хочу централизовать логику обработки всех необработанных исключений, используя Thread.GetDomain().UnhandledException мероприятие. Однако в моем приложении событие никогда не уволено для потоков, запущенных с CDPL, например, Task.Factory.StartNew(...). Отказ Событие действительно уволено, если я использую что-то вроде new Thread(threadStart).Start().

Эта статья MSDN предлагает использовать задачу. Wait () поймать AggregateException При работе с TPL, но это не то, что я хочу, потому что этот механизм не «централизован» достаточно.

Кто-нибудь испытывает та же проблема вообще или это только я? У вас есть решение для этого?

Это было полезно?

Решение 2

Похоже, нет встроенного способа справиться с этим (и нет ответа на этот вопрос после почти 2 недель). Я уже развернул какой-то заказчивый код, чтобы позаботиться об этом. Описание решения довольно длинно, поэтому я опубликовал в моем блоге. Ссылаться на эта почта если тебе интересно.

Обновление 5/7/2010: Я нашел лучший способ сделать это, используя продолжение задач. Я создаю А. class ThreadFactory Это открывает событие ошибки, которое может быть подписано обработчиком верхнего уровня и предоставляет способы начать задачу, прикрепленную с надлежащим продолжением.
Код опубликован здесь.

Обновление 4/18/2011: Почтовый код из поста блога в соответствии с комментарию 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();
    }
}

Другие советы

я думаю Taskscheduler.unobservedtaskexception событие это то, что вы хотите:

Возникает, когда не поврежден Задачи Необязательное исключение состоит в том, чтобы вызвать политику эскалации исключения, которая по умолчанию прекращает процесс.

Итак, это событие похоже на DomainUnhandledException Что вы упомянули на вашем вопросе, но возникают только для задач.

BTW Примечание, что ненаблюдаемая политика исключения (да, это не ненаблюдаемые исключения, MS, ребята, снова изобрели новое слово ... снова), изменилось с .NET 4.0 до .NET 4.5. В .NET 4.0 ненаблюдаемое исключение приводит к прекращению обработки, но в .NET 4.5 - не. Это все потому, что новые асинхронные вещи, которые у нас будут в C # 5 и VB 11.

Я вижу два варианта, которые можно использовать для целей централизации обработки исключений в TPL: 1. Использование неповрежденного события исключения задачи планировщика задач. 2. Использование продолжений для задач с неисправным состоянием.

Использование неповрежденного события исключения задачи планировщика задач.

Планировщик задач имеет событие unobservedTaskexception, к которому вы можете подписаться с использованием оператора + =.

  • ПРИМЕЧАНИЕ 1. В корпусе обработчика вам необходимо сделать вызов setobserved () на аргументе unobservedtaskexceptioneventargs, чтобы уведомить планировщик, что исключение было обработано.
  • ПРИМЕЧАНИЕ 2. Обработчик вызывается, когда задачи собираются сборщиком мусора.
  • ПРИМЕЧАНИЕ 3. Если вы будете ждать задачи, вы все равно будут вынуждены защищать ожидание, попробуйте / Catch Block.
  • Примечание 4: Политика по умолчанию для необработанных исключений задач в .NET 4.0 и 4.5 отличается.

Резюме: Этот подход хорош для задач с огнями и забытью, и для ловли исключений сбежал из централизованной политики обработки исключений.

Использование продолжений для задач с неисправным состоянием.

С помощью TPL вы можете прикрепить действия к задаче с использованием метода Steatherwith (), который принимает прикрепление действия и параметр продолжения. Это действие будет вызываться после прекращения задач и только в случаях, указанных путем опции. Особенно:

    t.ContinueWith(c => { /* exception handling code */ },
                   TaskContinuationOptions.OnlyOnFaulted);

Установите продолжение с помощью кода обработки исключений к задаче T. Этот код будет работать только в случае, когда задача T была прекращена из-за необработанного исключения.

  • Примечание 1: Получите значение исключения в процессе обработки исключений. В противном случае это будет выпукло.
  • Примечание 2: Код обработки исключений будет вызываться сразу после завершения задачи.
  • Примечание 3: Если исключение было получено в процессе обработки исключений, он будет рассматриваться как обрабатываемый, попробуйте / Catch Block на задаче ожидания не сможет его поймать.

Я думаю, что это будет лучше для централизованного обращения с исключением для использования пользовательских задач, унаследованных от задачи, с добавлением обработчика исключений с добавлением через продолжение. И сопровождать этот подход, используя неповрежденное исключение за исключением задачи планировщика задач, чтобы поймать попытки использовать не настроенные задачи.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top