Глобальная обработка исключений в многопоточных джунглях - Fail Safe / Restart - PullRequest
2 голосов
/ 10 января 2012

Ситуация:
У меня довольно сложное консольное приложение, запускающее несколько потоков, каждый из которых генерирует подпотоки и т. Д. (Для 3 или 4 уровней).Все в основном делегат / события.Я знаю, что блоки try / catch в области, где создается поток, не имеют отношения к этому потоку, когда он начинает выполняться.Я хочу найти простой способ управления этим.

В целях иллюстрации в моем приложении часто встречается следующий шаблон:

    public void Activate()
    {
        ThreadPool.QueueUserWorkItem(Activate_Entrypoint);    
    }

Проблема:
Пока я все еще занимался разработкой / отладкой, на микроуровне возникали исключения "на ходу".
Однако сейчас мне нужно собрать и подготовить производственный пакет, поэтому в случае необходимости все должно работать гладкоисключения.Поэтому мне нужно чистое сообщение пользователя / журнал и выключение / перезапуск на верхнем уровне.

Режим повышения исключений:
Я реализовал OnUnhandledException

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);

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

ВАЖНО - Чистый дизайн:
Мне нужна главная вершинаНить, чтобы быть просто в двух словах, с наблюдателем на остальной части приложения.Если возникает критическая ошибка, я бы хотел, чтобы этот поток остановил все (прерывание запущенного дочернего потока приложения), а затем Перезапустите его снова .Вы слышали это: я не хочу, чтобы ужасная авария просто остановила все.Я хотел бы изолировать приложение в потоке-обертке, который позаботился бы о том, чтобы оно все еще работало, и перезапустить его (это приложение на стороне сервера 24/7).Я также хотел бы избежать обработки всех возможных исключений везде, где это было бы адом.Я просто хочу, чтобы ремень безопасности позволял непредвиденным исключениям срабатывать, если они случаются, и аккуратно управлял ими, перезапуская приложение из главной верхней нити.

Возможные решения:
Я наткнулся на несколько сообщений о передаче флага и регулярной проверке потока.Это звучит интересно, хотя это может усложниться при использовании большого количества уровней потоков.Я использую Quartz.net, чтобы запланировать задачу постоянного сканирования некоторых флагов и принять меры, чтобы остановить и перезапустить потоки, если это необходимо.Еще не закончил, просто попробую.

Если я что-то пропустил, пожалуйста, потерпите меня и просто спросите детали, это не та область, с которой мне действительно удобно (пока нет).

Ресурсы: Джозеф Албахари о потоках /

1 Ответ

3 голосов
/ 10 января 2012

Проблема, с которой вы сталкиваетесь, описана в этой документации MSDN :

Необработанные исключения в потоках пула потоков завершают процесс.Из этого правила есть три исключения:

Исключение ThreadAbortException вызывается в потоке пула потоков, поскольку вызывается прерывание.

Исключение AppDomainUnloadedException выбрасывается в поток пула потоков, поскольку домен приложениябудучи выгруженным.

Общеязыковая среда выполнения или хост-процесс завершает поток.

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

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

Основываясь на этой информации, вам придется обрабатывать исключения в каждом из родительских потоков.

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

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

Затем, когда основной поток выполнит свой следующий проход, он увидит, что дочерние потоки умерли, и при необходимости перезапустит их.

Мы работали сэта же базовая конструкция, по крайней мере, 10 лет (мы запустили ядро ​​в VB6), и она работала очень хорошо в ряде различных конфигураций и нагрузок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...