ThreadAbortException

Ove*_*ose 43 .net c#

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

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

    while (true) {

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

    }
}
Run Code Online (Sandbox Code Playgroud)

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

Jos*_*osh 70

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

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

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

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

  • +1.只是不要中止线程,这绝不是一个好主意. (20认同)
  • 你可以停止使用Thread.ResetAbort()重新抛出它不是吗? (3认同)
  • 当你这样做时,你的代码闻起来像腐烂的鱼是完全正确的.但是,[ASP.net使用它来实现`Response.Redirect`](http://support.microsoft.com/kb/918181),当然使用`Thread.ResetAbort`重置,所以在这种情况下他们可以发生.没有帮助的情况是.NET框架[没有强化异步异常](http://goo.gl/FBKioJ)所以即使ASP.net使用它们,它仍然是一个非常糟糕的主意. (3认同)
  • @PietervanGinkel,我认为最大的区别是`Response.Redirect`不会异步中止另一个线程; 它会中止*本身*.这不是一个异步的线程中止.这就是为什么它是一种安全的方法.此外,它没有多少选择.它不得不完全中断处理,解除堆栈并将线程返回到线程池,无论客户端代码是什么样的.这几乎是唯一的方法. (2认同)

Jon*_*eet 20

是.我怀疑你问的是因为线程中断只发生在一个线程否则会阻塞(或者它已经被阻塞) - 例如对于IO.

中止没有这样的保证.它可以在任何时候发生,基本上,虽然有延迟中止区域,例如约束执行区域和catch/finally块,其中中止请求只是被记住,并且线程在退出区域时中止.

同步线程中止(即中止自己的线程)是相当安全的,但异步中止(中止不同的线程)几乎总是一个坏主意.阅读Joe Duffy的"Windows上的并发编程"以获取更多信息.

编辑:如下面Eric所述,中止另一个线程并不能保证实际上也有任何影响.只是引用评论:

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

  • 谢谢,乔恩.我的大脑刚刚吹了一个断路器. (3认同)
  • 很好的回答乔恩,我唯一的评论是,我会说,该线程被中止*如果*退出该地区,强调'Thread.Abort`是完全不可靠.如果循环位于这样的区域中,则因为它被卡在无限循环中而被中止的线程将不会中止.这是"Thread.Abort"是个坏主意的另一个原因; 如果你不能依靠实际发生的预期效果那么你为什么要调用这个方法呢? (3认同)

Ily*_*luk 7

实际上,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();
    } 
    
    Run Code Online (Sandbox Code Playgroud) 输出:
    First
    

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