可以在 catch 块之外抛出 ThreadAbortException 吗?

问题描述 投票:0回答:4

假设我们有一些像这样的代码在单独的线程中运行:

private static void ThreadFunc() {
    ulong counter = 0;

    while (true) {

        try {
            Console.WriteLine( "{0}", counter++ );
        }
        catch (ThreadAbortException) {
            Console.WriteLine( "Abort!" );
        }

    }
}

当调用

Thread.Abort()
时,是否有可能在catch块之外抛出异常?

c# .net exception threadabortexception
4个回答
77
投票

其实是的,一个

ThreadAbortException
很特别。即使你处理了它,它也会在 try/catch/finally 结束时被 CLR 自动重新抛出。 (正如评论中所指出的,它可以用
ResetAbort
来抑制,但到那时代码闻起来像烂鱼。)

更不用说,即使在 try/catch/finally 之外没有明显的可执行代码,循环的每次迭代都会在短时间内超出范围,因此中止可能会在 try 块之外发生。

除非你实际上在 catch 块中做一些事情,否则我只会尝试/最后,而不用担心

ThreadAbortException
。有很多更好的方法可以在不使用
Thread.Abort
的情况下中止线程,这不仅会在不可预测的点上混乱地中断您的代码,而且也不能保证它能正常工作,因为如果您的线程当前正在调用某些非托管代码,则该线程将不会中止直到控制权返回到托管代码。

最好使用某种类型的同步原语(例如

ManualResetEvent
)作为告诉线程何时退出的标志。您甚至可以使用布尔字段来达到此目的,这就是BackgroundWorker 所做的。


21
投票

是的。我怀疑你问这个问题是因为线程中断仅在线程可能阻塞(或者它已经被阻塞)时发生 - 例如对于 IO。

没有这样的中止保证。基本上,它可以在任何时候发生,尽管存在“延迟中止”区域,例如“约束执行区域”和 catch/finally 块,其中中止请求只是被记住,并且线程在退出该区域时中止。 同步线程中止(即中止您自己的线程)相当安全,但异步中止(中止不同的线程)几乎总是一个坏主意。阅读 Joe Duffy 所著的 “Windows 上的并发编程” 了解更多信息。

编辑:正如下面 Eric 所指出的,中止另一个线程也不能保证实际上有任何效果。只是引用评论: 我会说,如果退出该区域,线程就会中止,强调

Thread.Abort

是完全不可靠的。如果循环位于这样的区域,则由于陷入无限循环而被中止的线程将不会中止。这也是

Thread.Abort
是一个坏主意的另一个原因;如果您不能依赖实际发生的预期效果那么为什么要调用该方法?

实际上,
ThreadAbortException
是特殊的,如果它是由CLR或

Thread.Abort
方法抛出的。比较输出:

7
投票

稍微修改了 Joe Duffy 的“Windows 上的并发编程”示例(添加了 Console.WriteLine)。它通过 Thread.CurrentThread.Abort 抛出异常: try { try { Thread.CurrentThread.Abort(); } catch (ThreadAbortException) { Console.WriteLine("First"); //Try to swallow it. } //CLR automatically reraises the exception here . } catch (ThreadAbortException) { Console.WriteLine("Second"); Thread.ResetAbort(); //Try to swallow it again . } //The in - flight abort was reset , so it is not reraised again . 输出: 第一 第二

    修改前面的示例以使用不同的 ThreadAbortException 实例创建方法:
  • try { try { // get non-public constructor var cstor = typeof(ThreadAbortException) .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); // create ThreadAbortException instance ThreadAbortException ex = cstor.Invoke(null) as ThreadAbortException; // throw.. throw ex; } catch (ThreadAbortException) { Console.WriteLine("First"); } } catch (ThreadAbortException) { Console.WriteLine("Second"); Thread.ResetAbort(); }
    输出:
    
    第一
    
    
  • 看起来
    Thread的
    方法在内部调用本机代码,这使得引发的异常变得特定。
        
我不是100%符合你的要求,但我想指出你永远无法吞下

ThreadAbortException

:

4
投票

当调用 Abort 时 销毁线程的方法,常见的 语言运行时抛出 ThreadAbortException

ThreadAbortException
是一个特殊的 可以捕获的异常

,但是它
  将自动再次提高
  catch 块的末尾。
您是否在问是否可以捕获用
ThreadAbortException
在另一个线程中抛出的
try/catch
? 如果这是你的问题,那么不,你不能。

© www.soinside.com 2019 - 2024. All rights reserved.