StackruException в.NET >= 4.0 - дает возможность другим потокам корректно завершить работу
Есть ли способ, как по крайней мере отложить завершение управляемого приложения (на несколько десятков миллисекунд) и установить какой-либо общий флаг, чтобы дать другим потокам возможность изящно завершить работу (сам поток SO, очевидно, не будет выполнять ничего дальше)? Я собираюсь использовать для этого JIT-отладчик или хостинг CLR - мне любопытно, если кто-нибудь пробовал это раньше.
Почему я хочу сделать что-то не так?
Не вдаваясь в подробности - представьте себе эту аналогию - вы находитесь в казино, делающем ставки на рулетку, и вдруг обнаруживаете, что рулетка ненадежная фальшивка. Таким образом, вы хотите немедленно покинуть казино, НО, скорее всего, хотите сначала собрать свои ставки со стола. К сожалению, я не могу использовать отдельный процесс для этого, поскольку существуют очень жесткие требования к производительности.
Пробовал и не работал:
Поведение.NET для StackruException (и противоречащей информации в MSDN) обсуждалось несколько раз на SO - чтобы быстро подвести итог:
HandleProcessCorruptedStateExceptionsAttribute (например, в обработчике необработанных исключений appdomain) не работает
ExecuteCodeWithGuaranteedCleanup не работает
legacyUnhandledExceptionPolicy не работает
Может быть несколько других попыток обработать исключения StackruException - но очевидно, что CLR завершает весь процесс, как упомянуто в этом замечательном ответе Ханса Пассанта.
Учитывая попробовать:
- Отладчик JIT - оставьте поток за исключением замороженного, установите какой-либо общий флаг (вероятно, в закрепленном месте) и оттаивайте другие потоки на короткое время.
- Хостинг CLR и настройка политики необработанных исключений
У тебя есть другая идея? Или какой-либо опыт (успешный / неудачный) с этими двумя способами?
2 ответа
Слово "подделка" не совсем подходит для аналогии с вашим казино. Произошло землетрясение магнитудой 9 баллов, здание казино и стол для рулетки, оставшиеся фишки и игрок исчезли в гигантском облаке дыма и пыли.
Единственный способ запустить код после SOE - это держаться подальше от этого казино, оно должно выполняться в другом процессе. "Защитный" процесс, который запускает вашу неправильно работающую программу, он может использовать Process.ExitCode для обнаружения сбоя. Это будет -1073741571 (0xc00000fd). Состояние процесса исчезло, вам придется использовать один из внепроцессных методов взаимодействия.NET (например, WCF, именованные каналы, сокеты, отображенный в память файл), чтобы процесс защиты знал о том, что необходимо сделано для очистки. Это должно быть транзакционным, вы не можете судить о точном моменте времени, когда произошел сбой, так как он мог умереть при обновлении защиты.
Имейте в виду, что это редко стоит усилий. Потому что SOE довольно неотличима от ежедневного прерывания процесса. Как быть убитым диспетчером задач. Или машина теряет мощность. Или подвергаясь воздействию землетрясения:)
StackruException
это немедленное и критическое исключение, из которого среда выполнения не может восстановиться, поэтому вы не можете ее перехватить, восстановить или что-то еще. Чтобы запустить другой метод (будь то метод очистки или что-то еще), вы должны иметь возможность создать кадр стека для этого метода, и стек уже заполнен (вот что StackruException
средства!). Вы не можете запустить другой метод, потому что запуск метода - это то, что вызывает исключение в первую очередь!
К счастью, такое исключение всегда вызвано структурой программы. Вы должны быть в состоянии диагностировать и исправить ошибку в своем коде: когда вы получите исключение, вы увидите в стеке вызовов, что есть цикл из одного или нескольких методов, повторяющихся бесконечно. Вам нужно определить, что такое неисправная логика, и исправить ее, и это будет намного проще, чем пытаться исправить нефиксированное исключение.