Уничтожение потоков
Модель совместной отмены используется для остановки потока. Однако иногда невозможно остановить поток совместно, так как он запускает сторонний код, не предназначенный для совместной отмены. В приложениях платформа .NET Framework можно использовать Thread.Abort метод для принудительного завершения управляемого потока. При вызове Abort общеязыковая среда выполнения создает в целевом потоке исключение ThreadAbortException, которое целевой поток может перехватить. (Однако среда выполнения платформа .NET Framework всегда автоматически повторно создает исключение после catch
блока.) Дополнительные сведения см. в статье Thread.Abort.
Метод Thread.Abortне поддерживается в .NET 5 (включая .NET Core) и более поздних версиях. Если необходимо принудительно завершить выполнение кода сторонних производителей в .NET 5 или более поздней версии, запустите его в отдельном процессе и воспользуйтесь Process.Kill.
Примечание.
- При вызове Thread.Abort прерывания потока, отличного от текущего потока, вы не знаете, какой код выполнил или не удалось выполнить при ThreadAbortException возникновении. Вы также не можете быть уверены в состоянии приложения или любого приложения и пользовательского состояния, которое оно отвечает за сохранение. Например, вызов Thread.Abort может препятствовать выполнению статических конструкторов или выпуску управляемых или неуправляемых ресурсов.
- Если в потоке выполняется неуправляемый код при вызове его метода Abort, в среде выполнения он отмечается как ThreadState.AbortRequested. В этом случае исключение вызывается после возврата потока в управляемый код.
После прерывания поток не перезапускается.
Метод Abort не приводит к немедленному прерыванию потока, так как целевой поток может перехватить ThreadAbortException и выполнить любой объем кода в блоке finally
. Если необходимо дождаться завершения потока, вы можете вызвать Thread.Join. Блокирующий вызов Thread.Join не завершится, пока поток полностью не закончит выполнение или не истечет указанный (необязательный) интервал времени ожидания. Прерванный поток может вызвать метод ResetAbort или выполнить любой объем операций в блоке finally
, поэтому завершение ожидания не гарантируется, если вы не укажете время ожидания.
Потоки, ожидающие завершения метода Thread.Join, могут быть прерваны другими потоками, которые вызывают Thread.Interrupt.
Обработка ThreadAbortException
Если вы ожидаете, что поток будет прерван вызовом Abort из вашего кода или в результате выгрузки домена приложения, в котором выполняется поток (AppDomain.Unload использует Thread.Abort для прерывания потоков), в таком потоке необходимо обработать ThreadAbortException, включив в предложение finally
все операции последней обработки, как показано в следующем примере.
Try
' Code that is executing when the thread is aborted.
Catch ex As ThreadAbortException
' Clean-up code can go here.
' If there is no Finally clause, ThreadAbortException is
' re-thrown by the system at the end of the Catch clause.
Finally
' Clean-up code can go here.
End Try
' Do not put clean-up code here, because the exception
' is rethrown at the end of the Finally clause.
try
{
// Code that is executing when the thread is aborted.
}
catch (ThreadAbortException ex)
{
// Clean-up code can go here.
// If there is no Finally clause, ThreadAbortException is
// re-thrown by the system at the end of the Catch clause.
}
// Do not put clean-up code here, because the exception
// is rethrown at the end of the Finally clause.
Код завершения работы следует поместить в предложении catch
или finally
, так как система повторно создаст исключение ThreadAbortException в конце предложения finally
или catch
, если отсутствует предложение finally
.
Чтобы предотвратить повторное создание исключения, вы можете вызвать метод Thread.ResetAbort. Но этот вариант следует использовать только в том случае, если ThreadAbortException вызывается в пользовательском коде.