Исключение прерывания потока в WPF
Я пытаюсь реализовать загрузчики в моем WPF
приложение. Во время некоторых тяжелых операций поток пользовательского интерфейса зависает, поэтому мне пришлось реализовать загрузчики с использованием потоков. Каждый раз, когда загружается загрузчик, создается новый поток, и этот поток прерывается (вручную), когда загрузчик запускается. Проблема, с которой я сталкиваюсь, заключается в том, что иногда происходит сбой приложения, давая ThreadAbortException
,
Это код для запуска загрузчика:
try
{
//if(newWindowThread !=null && !newWindowThread.IsAlive) { }
newWindowThread = new Thread(new ThreadStart(() =>
{
try
{
// Create and show the Window
awq = new BusyIndicatorDisguise(BusyMessage);
awq.Show(); // <== POINT WHERE THE EXCEPTION IS THROWN
//Start the Dispatcher Processing
if (!isDispatcherStarted)
{
var a = Thread.CurrentThread;
var b = Dispatcher.CurrentDispatcher;
//isDispatcherStarted = true;
Dispatcher.Run();
}
}
catch (ThreadAbortException thEx)
{
}
catch (Exception ex)
{
}
}
));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}
catch (Exception ex)
{
}
Этот код для остановки загрузчика:
if (newWindowThread != null && newWindowThread.IsAlive)
{
newWindowThread.Abort();
}
Я не могу поймать это исключение в моем блоке catch. Может быть, потому что это в другой теме. Я хочу знать, как я могу избежать исключения ThreadAbortException
2 ответа
Если вы бросите исключение для себя, забудьте Thread.Abort
, Вот почему:
- Бросок исключения - чрезвычайно дорогая операция. Он сохраняет весь стек вызовов и другие полезные данные для отладки. В этом случае все, что вам нужно, это просто установить простой флаг.
ThreadAbortException
хитрый. Он автоматически перебрасывается в конце блока обработчика исключений, если вы не вызоветеThread.ResetAbort
вcatch
блок. Но НЕ делайте этого!ThreadAbortException
это асинхронное исключение, которое означает, что оно может произойти в любой точке вашего кода, что может привести к непредсказуемым результатам. Это инструмент грубой силы, такой как кнопка " Завершить задачу" в диспетчере задач. Используйте его, только если вы не можете переписать исполняемый код (сторонний компонент) и если вы уверены, что можете выгрузить остатки нестабильной среды выполнения (он выполняется вAppDomain
).
Вместо этого отправьте запрос отмены вашему загрузчику (может быть простым bool
), который вы должны регулярно опрашивать во время операции загрузки. Вот пример того, как вы можете сделать это с помощью BackgroundWorker
и изменчивое поле.
Вы должны добавить блок try catch в поток, который может вызвать исключение и управлять им в соответствии с вашими потребностями.
Во всяком случае, как @Josh говорит в другом подобном посте
Существуют гораздо лучшие способы прерывания потока без использования Thread.Abort, который не только хаотично прерывает ваш код в непредсказуемой точке, но и не гарантирует его работоспособность, поскольку если ваш поток в данный момент вызывает какой-то неуправляемый код, поток не будет прерываться пока управление не вернется к управляемому коду.
Намного лучше использовать некоторый тип примитива синхронизации, такой как aManualResetEvent, чтобы действовать как флаг, указывающий вашему потоку, когда выходить. Вы можете даже использовать логическое поле для этой цели, что и делает BackgroundWorker.