若要终止线程的执行,通常使用协作取消模型。 但有时无法以协作方式停止线程,因为它运行的第三方代码不是为协作取消而设计的。 在 .NET Framework 应用中,可以使用 Thread.Abort 方法强行终止托管线程。 调用 Abort 时,公共语言运行时在目标线程中引发目标线程可以捕获的 ThreadAbortException。 但是,.NET Framework 运行时总是在 catch 块后自动重新引发异常
.NET 5(包括 .NET Core)及更高版本不支持Thread.Abort 方法。 如果需要在 .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 { // 线程中止时执行的代码。 } catch (ThreadAbortException ex) { // 清理代码可以放在这里。 // 如果没有 Finally 子句,系统会在 Catch 子句的末尾重新引发 ThreadAbortException 异常。 } // 不要把清理代码放在这里,因为异常会在 Finally 子句的末尾重新引发。
清理代码必须位于 catch 子句或 finally 子句中,因为系统会在 finally 子句末尾或 catch 子句(如果没有 finally 子句的话)末尾重新抛出 ThreadAbortException。
可以调用 Thread.ResetAbort 方法,以防系统重新抛出异常。 不过,只有在自己的代码导致 ThreadAbortException 抛出时,才应这样做