因为终止线程并不一定意味着会抛出异常。对于“终止过程”,
catch (ThreadAbortException)
块只是另一个关键代码区域。它只提供了一种线程安全且方便的方式来检测当前线程是否正在被终止(可能还传递了一些状态),以防我们想要执行一些特殊操作。除此之外,它就像任何其他关键代码区域(比如 finally 块)一样,在执行后将终止线程。
与此同时,在您的示例中,
Abort
被同步调用(实际上是安全的),在这种情况下,它非常类似于抛出异常。只有当它被从另一个线程异步调用时,由于终止过程比仅仅抛出异常更加复杂,事情才变得有趣和危险:实质上,首先标记线程为已终止,然后执行关键代码区域(例如 finally 块),只有在线程上的
AbortRequested 标志仍被设置时才会抛出异常,等等。
下面的代码说明了这个事实,它可以在不捕获任何异常的情况下恢复已终止的线程:
var inFinally = new ManualResetEvent(false);
var abortCalled = new ManualResetEvent(false);
var t = new Thread(_ =>
{
Console.WriteLine("Thread started..");
try
{
}
finally
{
inFinally.Set();
abortCalled.WaitOne();
Console.WriteLine(" ThreadState (before): " + Thread.CurrentThread.ThreadState);
if ((Thread.CurrentThread.ThreadState & ThreadState.AbortRequested) != 0)
{
Thread.ResetAbort();
}
Console.WriteLine(" ThreadState (after): " + Thread.CurrentThread.ThreadState);
}
Console.WriteLine("Executed because we called Thread.ResetAbort()");
});
t.Start();
inFinally.WaitOne();
ThreadPool.QueueUserWorkItem(_ => t.Abort());
while ((t.ThreadState & ThreadState.AbortRequested) == 0)
{
Thread.Sleep(1);
}
abortCalled.Set();
Console.ReadLine();
现在,我必须诚实地说:我不完全确定如何使用此功能并创建有用的东西。但听起来 Thread.Abort API 可能(可能仍然是,我不知道)被用于在像 ASP.NET 这样的框架中促进线程和 AppDomain 的重用。
在 Joe Duffy 的博客文章之一
Managed code and asynchronous exception hardening中,他谈到了 ResetAbort 和 Abort API:
“一些框架基础设施,尤其是 ASP.NET,甚至会定期中止单个线程而不卸载域。它们支持 ThreadAbortExceptions,调用 ResetAbort 在线程上并重用它或将其返回给 CLR ThreadPool。”
我可以想象它可以在框架中用于重用托管线程,从而减少开销。然而,由于这个容易被误解的 API 引入了用户代码中的问题(不良线程同步设计、不良异常处理、死锁等等),使得 Abort 和 ResetAbort 调用比有用更加麻烦。