销毁线程

若要终止线程的执行,通常使用协作取消模型。 但有时无法以协作方式停止线程,因为它运行的第三方代码不是为协作取消而设计的。 在 .NET Framework 应用中,可以使用 Thread.Abort 方法强行终止托管线程。 调用 Abort 时,公共语言运行时在目标线程中引发目标线程可以捕获的 ThreadAbortException。 (但是,.NET Framework 运行时总是在 catch 块后自动重新引发异常。)有关详细信息,请参阅 Thread.Abort

.NET 5(包括 .NET Core)及更高版本不支持Thread.Abort 方法。 如果需要在 .NET 5+ 中强制终止第三方代码的执行,请在单独的进程中运行该代码,并使用 Process.Kill

注意

  • 当调用 Thread.Abort 以中止当前线程以外的线程时,不知道引发 ThreadAbortException 异常时哪些代码已经执行,哪些代码未能执行。 你也不能确定应用程序的状态及其负责保留的任何应用程序和用户状态。 例如,调用 Thread.Abort 可能会阻止执行静态构造函数或释放托管或非托管资源。
  • 如果线程在调用 Abort 方法时执行的是非托管代码,运行时将它标记为 ThreadState.AbortRequested。 当线程返回到托管代码时,异常就会抛出。

一旦线程中止,就无法再重启。

Abort 方法不会导致线程立即中止,因为目标线程可以捕获 ThreadAbortException,并在 finally 块中执行任意数量的代码。 如果需要等到线程结束,可以调用 Thread.JoinThread.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 子句中,因为系统会在 finally 子句末尾或 catch 子句(如果没有 finally 子句的话)末尾重新抛出 ThreadAbortException

可以调用 Thread.ResetAbort 方法,以防系统重新抛出异常。 不过,只有在自己的代码导致 ThreadAbortException 抛出时,才应这样做。

另请参阅