2012-01-09 2 views
2

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

Для иллюстрации, следующая картина часто появляется на многих уровнях в моем приложении:

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

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

Исключение:
Я реализовал OnUnhandledException

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

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

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

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

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

Ресурсы: Joseph Albahari on Threading/

+0

Вам нужно получить приложение AppDomain.UnhandledException. Очень непонятно, почему у вас возникнут проблемы с этим. –

+1

Что касается того, что UnhandledException не вызывается, пытались ли вы явно исключать исключение, а не делить на ноль? Я не совсем уверен, но я считаю, что деление на ноль приведет только к исключению в «проверенном» контексте; по умолчанию компилятор будет использовать «непроверенную» арифметику и, таким образом, будет генерировать значения NaN или INF, а не бросать исключения. –

+0

Чтобы быть уверенным, существует только 1 (один) AppDomain? – rene

ответ

3

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

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

Ошибка ThreadAbortException в потоке пула потоков, поскольку вызывается Abort.

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

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

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

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

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

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

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

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

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

+0

Спасибо. является 'Thread.Abort()' изящным отключением? :) –

+0

Да. Это вызовет ThreadAbortException и, если это необработанно, .Net просто прекратит поток и не продолжит распространение исключения. –

+0

Hummm ... Хорошо, тогда. Я внимательно посмотрю. спасибо –