ThreadAbortException
Скажем, у нас есть некоторый код, подобный этому, в отдельном потоке:
private static void ThreadFunc() {
ulong counter = 0;
while (true) {
try {
Console.WriteLine( "{0}", counter++ );
}
catch (ThreadAbortException) {
Console.WriteLine( "Abort!" );
}
}
}
Когда вызывается Thread.Abort()
, возможно ли, что исключение выбрано вне блока catch?
Ответы
Ответ 1
На самом деле да, ThreadAbortException
является особенным. Даже если вы справитесь с этим, он будет автоматически перезагружен CLR в конце try/catch/finally. (Как отмечено в комментариях, его можно подавить с помощью ResetAbort
, но к этому моменту код пахнет гнилой рыбой.)
Не говоря уже о том, что нет очевидного исполняемого кода вне вашего try/catch/, наконец, каждая итерация цикла завершается за пределами области действия в течение небольшой продолжительности, поэтому прерывание может происходить вне вашего блока try.
Если вы на самом деле ничего не делаете в блоке catch, я просто сделаю попытку/наконец и не беспокоюсь о ThreadAbortException
. Есть намного лучшие способы отменить поток, не используя Thread.Abort
, который не только хаотично прерывает ваш код в непредсказуемой точке, но и не гарантированно работает, потому что если ваш поток в настоящее время вызывает какой-то неуправляемый код, поток не прерывается пока управление не вернется к управляемому коду.
Гораздо лучше использовать некоторый тип примитива синхронизации, например ManualResetEvent
, чтобы действовать как флаг, сообщающий вашему потоку, когда выходить. Вы могли бы даже использовать для этой цели логическое поле, которое делает BackgroundWorker.
Ответ 2
Да. Я подозреваю, что вы спрашиваете, потому что прерывания потока происходят только тогда, когда поток может в противном случае заблокировать (или если он уже заблокирован) - например. для IO.
Нет такой гарантии для прерывания. Это может произойти в любое время, в основном, хотя существуют регионы с задержкой, такие как ограниченные области выполнения и блоки catch/finally, где запрос прерывания просто запоминается, и поток прерывается, когда он выходит из области.
Синхронные прерывания потока (т.е. прерывание собственного потока) достаточно безопасны, но асинхронные прерывания (прерывание другого потока) почти всегда являются плохими идеями. Прочтите "Параллельное программирование в Windows" Джо Даффи для получения дополнительной информации.
EDIT: Как отмечено Эриком ниже, отменить другой поток также не гарантирует никакого эффекта. Просто процитировать комментарий:
Я бы сказал, что поток прерывается, если он выходит из региона, подчеркивая, что Thread.Abort
является полностью ненадежным. Поток, который прерывается, поскольку он застревает в бесконечном цикле, не прерывается, если цикл находится в такой области. Это еще одна причина, по которой Thread.Abort
- плохая идея; если вы не можете полагаться на желаемый эффект, который на самом деле происходит, то почему вы бы назвали метод?
Ответ 3
Собственно, ThreadAbortException является особым в случае, если он вызывается методом CLR или Thread.Abort. Сравнить вывод:
- Немного измененный пример (добавлен Console.WriteLine) от Джо Даффи "Параллельное программирование в Windows". Он выдает исключение Thread.CurrentThread.Abort:
try
{
try
{
Thread.CurrentThread.Abort();
}
catch (ThreadAbortException)
{
Console.WriteLine("First");
//Try to swallow it.
} //CLR automatically reraises the exception here .
}
catch (ThreadAbortException)
{
Console.WriteLine("Second");
Thread.ResetAbort();
//Try to swallow it again .
} //The in - flight abort was reset , so it is not reraised again .
Вывод:
First
Second
-
Измените предыдущий пример, чтобы использовать другой подход создания экземпляра ThreadAbortException:
try
{
try
{
// get non-public constructor
var cstor = typeof(ThreadAbortException)
.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
// create ThreadAbortException instance
ThreadAbortException ex = cstor.Invoke(null) as ThreadAbortException;
// throw..
throw ex;
}
catch (ThreadAbortException)
{
Console.WriteLine("First");
}
}
catch (ThreadAbortException)
{
Console.WriteLine("Second");
Thread.ResetAbort();
}
Вывод:
First
Похоже, что методы Thread вызывают внутренний код внутри, что делает особый особый исключение.
Ответ 4
Я не на 100%, что вы просите, но я хотел бы указать, что вы никогда не сможете усвоить ThreadAbortException
При вызове Abort метод уничтожения потока, общий языковая среда запускает ThreadAbortException
. ThreadAbortException
является специальным исключение, которое можно поймать, но оно будет автоматически снова поднят конец блока catch.
Вы спрашиваете, можно ли поймать ThreadAbortException
, который был добавлен в другой поток с помощью try/catch
? Если это ваш вопрос, то нет, вы не можете.