Как обрабатывать AppDomain.Unload и связанные с ним ThreadAbortException
Согласно MSDN, AppDomain.Unload заставляет все потоки внутри выгружаемого AppDomain генерировать исключение прерывания потока.
Потоки в домене завершаются с помощью метода Abort, который создает исключение ThreadAbortException в потоке. Хотя поток должен завершиться быстро, он может продолжать выполняться в течение непредсказуемого периода времени в предложении finally. - из MSDN
Поэтому я понимаю, что каждый раз, когда я пишу код в любом месте, которое, как ожидается, будет запущено в этом домене приложений, я должен ожидать, что прерывание потока может произойти в любом потоке в любое время. Это правда? Должен ли весь код везде предполагать, что исключение ThreadAbortException может быть выдано в любое время?
Практически это фактически выявляет catch(Exception ex), потому что это перехватит ThreadAbortException и попытается его обработать, обычно путем регистрации ошибки, которая действительно не должна регистрироваться (поскольку выгрузка AppDomain на самом деле не является исключением).
Есть ли другие соображения, которые необходимо принять, чтобы избежать ненужной обработки исключений / регистрации ошибок?
2 ответа
Вы в значительной степени имеете правильное ожидание относительно возможности TAE в любое время. Единственное, что я хотел бы отметить, это то, что ваш код, вероятно, уже должен быть написан таким образом - при обработке данных, которые имеют требования к надежности, вы должны использовать транзакции или другие механизмы компенсации в случае аппаратного сбоя, ошибки оператора, OOM и т. Д. - любой из которых не являются уникальными для сценария закрытия AppDomain.
Наконец, вы должны знать, что вы можете перехватывать TAE и выполнять компенсационный код в блоке catch. Единственное, что в них особенного, это то, что они будут немедленно переброшены после блока захвата, так что вы не сможете "проглотить" их. Вы можете подавить их, используя Thread.ResetAbort()
, но в этом случае это, вероятно, не желаемый эффект.
Мы все написали такой код:
public void Foo() {
try {
Do.Some.Stuff();
} catch (Exception ex) {
Console.Out.WriteLine("Oh noes!");
}
}
И да, блок catch поймает все1, включая TAE и OOM.
Здесь нужно помнить, что для всех вышеперечисленных исключений мир в основном заканчивается. Все, что вас должно волновать, - это то, что любые важные для транзакций данные, с которыми вы имеете дело, не будут потеряны или оставлены в плохом состоянии, и поэтому мы обычно оставляем такие вещи, как транзакционно-безопасный ввод / вывод, умным людям в Microsoft и Oracle. кто пишет базы данных. Если ваш код выполняет, например, ввод / вывод с использованием плоских файлов, который вы должны быть уверены, что никогда не оставит файл в плохом состоянии, то вы должны думать о режимах сбоев очень целостным образом, например, "что произойдет, если отключается питание, когда этот файл наполовину записан? "
1 Единственным исключением является то, что исключения Stackru, как правило, не могут быть перехвачены. Это было изменение в.NET 2.0.
Вы не можете справиться ThreadAbortException
так что не нужно ловить исключение. Более технически
это специальное исключение, которое может быть перехвачено, но оно будет автоматически поднято снова в конце блока catch