若要终止线程的执行,通常使用 协作取消模型。 但是,有时无法以协作方式停止线程,因为它运行不用于协作取消的第三方代码。 在 .NET Framework 应用中,可以使用 Thread.Abort 该方法强行终止托管线程。 调用 Abort 时,公共语言运行时会在目标线程中引发一个 ThreadAbortException,目标线程可以捕获该异常。 (但是,.NET Framework 运行时总是在 catch 块之后自动重新引发异常)。有关详细信息,请参阅 Thread.Abort。
在 .NET Core 和 .NET 5 及更高版本中,方法 Thread.Abort 在运行时引发 PlatformNotSupportedException 。 从 .NET 5 开始,它还标记为已过时(SYSLIB0006),因此调用它将生成编译时警告。 如果需要在现代 .NET 实现中强行终止第三方代码的执行,请在单独的进程中运行它并使用 Process.Kill。
注释
- 调用 Thread.Abort 中止当前线程外的其他线程时,当 ThreadAbortException 被抛出时,你无法知道哪些代码已经执行或未执行。 你也不能确定应用程序的状态,也不能确定它负责保留的任何应用程序和用户状态。 例如,调用 Thread.Abort 可能会阻止执行静态构造函数或释放托管或非托管资源。
- 如果线程在调用其 Abort 方法时正在执行非托管代码,则运行时将标记它 ThreadState.AbortRequested。 当线程返回到托管代码时,将引发异常。
中止线程后,无法重新启动它。
该方法Abort不会导致线程立即中止,因为目标线程可以在finally代码块中捕获ThreadAbortException,并执行任意数量的代码。 如果需要等待线程结束,可以调用 Thread.Join 。
Thread.Join 是一个阻塞调用,只有当线程实际停止执行或者设置的超时间隔已结束时才会返回。 中止的线程可以调用 ResetAbort 该方法或在块中 finally 执行未绑定处理,因此如果不指定超时,则无法保证等待结束。
等待调用 Thread.Join 方法的线程可以被调用 Thread.Interrupt的其他线程中断。
处理 ThreadAbortException
如果你预期线程会被终止(无论是由于从自己的代码调用Abort,还是由于卸载运行线程的应用程序域(AppDomain.Unload使用Thread.Abort终止线程),那么线程必须在ThreadAbortException子句中处理异常并执行任何最终处理,如以下代码所示。
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 子句中,因为系统会在 finally 子句的末尾重新引发 ThreadAbortException,或者在没有 finally 子句的情况下,在 catch 子句的末尾重新引发。
可以通过调用 Thread.ResetAbort 该方法来阻止系统重新引发异常。 但是,仅当是自己的代码导致 ThreadAbortException时,才应执行此操作。