简体   繁体   English

ThreadAbortException

[英]ThreadAbortException

Let's say we have some code like this running in the separate thread: 假设我们有一些类似的代码在单独的线程中运行:

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

    while (true) {

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

    }
}

When Thread.Abort() is called, is it possible that the exception is thrown outside of catch block? 调用Thread.Abort() ,是否有可能将异常引发到catch块之外?

Actually yes, a ThreadAbortException is special. 实际上是的, ThreadAbortException是特殊的。 Even if you handle it, it will be automatically re-thrown by the CLR at the end of the try/catch/finally. 即使您处理了它,它也会在try / catch / finally之后由CLR自动重新抛出。 (As noted in the comments, it can be suppressed with ResetAbort but by that point the code smells like rotten fish.) (如注释中所述,可以使用ResetAbort抑制它,但是到那时,代码闻起来就像烂鱼一样。)

Not to mention even though there is no obvious executable code outside of your try/catch/finally, every iteration of the loop winds up outside of the scope for a small duration so the abort could occur outside of your try block. 即使在try / catch / finally之外没有明显的可执行代码,更不用说,循环的每次迭代都会在作用域之外停留一小段时间,因此中止可能发生在try块之外。

Unless you are actually doing something in the catch block, I would just make a try/finally and don't worry about ThreadAbortException . 除非您实际上是在catch块中做某事,否则我只会尝试一下/最后,不要担心ThreadAbortException There are much better ways of aborting a thread without using Thread.Abort which not only chaotically interrupts your code at an unpredictable point, it's also not guaranteed to work because if your thread is currently calling out to some unmanaged code, the thread will not abort until control returns to managed code. 有很多更好的方法可以在不使用Thread.Abort情况下中止线程,它不仅会在无法预测的点混乱地中断您的代码,而且还不能保证正常工作,因为如果您的线程当前正在调用某些非托管代码,则该线程将不会中止直到控制权返回到托管代码。

It's much better to use some type of synchronization primitive such as a ManualResetEvent to act as a flag telling your thread when to exit. 最好使用某种类型的同步原语,例如ManualResetEvent作为标记,告诉您的线程何时退出。 You could even use a boolean field for this purpose which is what the BackgroundWorker does. 您甚至可以为此使用一个布尔字段,这是BackgroundWorker所做的。

Yes. 是。 I suspect that you're asking because thread interruptions only occur when a thread could otherwise block (or if it's already blocked) - eg for IO. 怀疑您在问,因为线程中断仅在线程可能会以其他方式阻塞(或是否已经阻塞)时发生(例如,对于IO)。

There's no such guarantee for abort. 没有这样的保证可以中止。 It can happen at any time, basically, although there are delay-abort regions such as constrained execution regions and catch/finally blocks, where the abort request is just remembered, and the thread aborted when it exits the region. 基本上,它可以在任何时间发生,尽管存在延迟中止区域(例如受约束的执行区域和catch / finally块),只是记住了中止请求,而线程在退出该区域时中止了。

Synchronous thread aborts (ie aborting your own thread) is reasonably safe, but asynchronous aborts (aborting a different thread) are almost always a bad idea. 同步线程中止(即中止自己的线程)是相当安全的,但是异步中止(中止另一个线程)几乎总是一个坏主意。 Read "Concurrent Programming on Windows" by Joe Duffy for further information. 有关更多信息,请阅读Joe Duffy的“ Windows上的并行编程”

EDIT: As noted by Eric below, aborting another thread isn't guaranteed to actually have any effect either. 编辑:正如下面的埃里克(Eric)所述,中止另一个线程也不能保证实际上有任何效果。 Just to quote the comment: 仅引用评论:

I would have said that the thread is aborted if it exits the region, emphasizing that Thread.Abort is completely unreliable. 我会说, 如果线程退出该区域,则会中止该线程,强调Thread.Abort是完全不可靠的。 A thread which being aborted because it is stuck in an infinite loop will not abort if the loop is in such a region. 如果一个线程陷入无限循环而被中止,则该循环不会在该区域中中止。 This is yet another reason why Thread.Abort is a bad idea; 这是Thread.Abort不好的另一个原因。 if you can't rely on the desired effect actually happening then why would you call the method? 如果您不能依靠实际发生的预期效果,那为什么要调用该方法呢?

Actually, ThreadAbortException is special in case it's thrown by CLR or Thread.Abort method. 实际上, ThreadAbortException是特殊的,以防被CLR或Thread.Abort方法抛出。 Compare output: 比较输出:

  • Slightly modified example (added Console.WriteLine) from Joe Duffy's "Concurrent Programming on Windows". Joe Duffy的“ Windows并发编程”中的示例稍作修改(添加了Console.WriteLine)。 It throws the exception by Thread.CurrentThread.Abort: 它通过Thread.CurrentThread.Abort引发异常:
    \ntry { 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 .\ntry { 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 . 
    Output: 输出:
    \nFirst 第一\nSecond 第二\n
  • Modify previous example to use different approach of ThreadAbortException instance creation: 修改前面的示例以使用不同的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(); } 
    Output: 输出:
    \nFirst 第一\n

It seems like Thread's methods call native code internally which makes raised exception specific. 似乎Thread的方法在内部调用本机代码,这使引发的异常特定。

I am not 100% what you are asking but I wanted to point out that you will never be able to swallow a ThreadAbortException : 我不是100%的要求,但我想指出,您将永远无法吞下ThreadAbortException

When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException . 调用Abort方法销毁线程时,公共语言运行库将抛出ThreadAbortException ThreadAbortException is a special exception that can be caught , but it will automatically be raised again at the end of the catch block. ThreadAbortException是可以捕获的特殊异常 ,但是它将在catch块的末尾自动再次引发。

Are you asking if it is possible to catch a ThreadAbortException that is thrown in another thread here with a try/catch ? 您是否在问是否可以使用try/catch在另一个线程中抛出的ThreadAbortException If that is your question, then no, you cannot. 如果这是您的问题,那么不会,您不能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM