ThreadAbortException

时间:2009-12-06 19:16:30

标签: c# .net

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

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

    while (true) {

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

    }
}

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

4 个答案:

答案 0 :(得分:67)

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

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

除非你实际上在catch块中做了一些事情,否则我只是试一试/最后不要担心ThreadAbortException。有一些更好的方法可以在不使用Thread.Abort的情况下中止线程,这不仅会在不可预测的地点混乱地中断你的代码,而且也不能保证工作,因为如果你的线程当前正在调用一些非托管代码,那么线程就会在控制权返回托管代码之前不会中止。

使用某种类型的同步原语(如ManualResetEvent)作为一个标志告诉您的线程何时退出会更好。您甚至可以为此目的使用布尔字段,这是BackgroundWorker所做的。

答案 1 :(得分:20)

是。我怀疑您正在询问,因为线程中断仅在线程可能阻止(或者如果它已被阻止)时发生 - 例如对于IO。

对于中止没有这样的保证。它可以在任何时候发生,基本上,虽然有 delay-abort 区域,例如constrained execution regions和catch / finally块,其中中止请求只是被记住,并且线程在它被中止时退出该地区。

同步线程中止(即中止自己的线程)是相当安全的,但异步中止(中止不同的线程)几乎总是一个坏主意。请阅读"Concurrent Programming on Windows" by Joe Duffy以获取更多信息。

编辑:正如下面的Eric所说,中止另一个线程并不能保证实际上也有任何效果。只是引用评论:

  

如果它离开该区域,我会说该线程被中止,强调Thread.Abort完全不可靠。如果循环位于这样的区域中,则因为它被卡在无限循环中而被中止的线程将不会中止。这是Thread.Abort一个坏主意的另一个原因;如果你不能依靠实际发生的预期效果那么你为什么要调用这个方法?

答案 2 :(得分:6)

实际上, ThreadAbortException 是特殊的,以防它被CLR或 Thread.Abort 方法抛出。比较输出:

  • 来自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 .
    
    
    
    输出:
    First
    Second
    
  • 修改前面的示例以使用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();
    } 
    
    输出:
    First
    

似乎 Thread的方法在内部调用本机代码,这使得引发的异常特定。

答案 3 :(得分:4)

我不是100%你问的是什么,但我想指出你永远无法吞下ThreadAbortException

  

拨打中止电话时   破坏线程的方法,常见的   语言运行时抛出一个   ThreadAbortException。    ThreadAbortException很特别   可以捕获的异常 ,但它   将自动再次提升   捕获块结束。

您是否可以通过ThreadAbortException询问是否可以捕获另一个线程中引发的try/catch?如果这是你的问题,那么不,你不能。