2011-10-03 56 views
3

假设扔我有这样的代码:为什么ThreadAbortException不catch块

static void Main(string[] args) 
    { 
     var thread = new Thread(() => 
     { 
      try 
      { 
       throw new InvalidOperationException(); 
      } 
      catch (Exception) 
      { 
       Thread.Sleep(Timeout.Infinite); 
      } 
     }); 
     thread.Start(); 

     Thread.Sleep(TimeSpan.FromSeconds(1)); 

     thread.Abort(); 
     thread.Join(); 
    } 

它启动线程,那么线程进入在catch块睡眠之后,我们正试图中止线程。

中止方法必须引发ThreadAbortException。但是在catch块中它不会发生。 这是documented

调用如果被 中止线程的代码保护的区域,如catch块中止可能会阻塞线程, finally块,或约束的执行区域。如果 调用中止的线程持有中止线程所需的锁定,则会发生死锁 。

我的问题是为什么。它为什么这样工作?因为在catch块中,我们可以提出任何异常和所有需要的作品。

UPDATE: 从link通过Jordão酒店。接受,因为这是最容易理解的澄清。

约束的执行区域的.NET Framework 2.0引入 约束的执行区域(CER),其中两个上 运行时和在显影剂施加限制。在被标记为CER的代码区域中,运行时限制不会抛出某些异常,这会阻止该区域在其整个 中执行。开发人员也可能在该地区执行的操作受到限制。这创建了一个框架和执行 机制来编写可靠的托管代码,使其成为.NET Framework 2.0的可靠性故事中的关键角色 。运行时间为 以应对其负担,它为CERs提供了两种便利。首先, 运行时将延迟在CER中执行的代码的线程中止。 换句话说,如果一个线程调用Thread.Abort来放弃当前在一个CER内执行的另一个线程 ,那么运行时不会中止目标线程的 ,直到执行离开CER。其次,运行时将尽可能快地准备CER,以避免 内存不足的情况。这意味着运行时将在代码区域的 JIT编译期间通常执行的所有操作都会执行 。它还将探测一定数量的免费堆栈空间来帮助消除堆栈溢出异常。通过预先执行此项工作,运行时可以更好地避免区域内可能发生的异常,并防止资源被适当清理 。要有效使用CER,开发人员应避免可能导致异步异常的某些操作。代码 受限于执行某些操作,包括显式分配,装箱,虚拟方法调用(除非虚拟方法调用的目标 已准备好),方法调用 通过反射,使用Monitor等。输入(或在C# 和为SyncLock在VisualBasic®lock关键字),在 COM对象isinst和castclass指令,通过透明代理字段访问,序列化 和多维数组访问。总之,核证减排量的代码运行之前移动 从你的代码的任何运行时引发的故障点的时间要么 (JIT在编译的情况下)的方式,或代码 完成后(线程中止)。但是,CERs确实会限制您可以编写的代码 。诸如不允许大多数分配 或对未准备目标的虚拟方法调用的限制是重要的, 意味着编写它们的高开发成本。这意味着核证减排量 不适合的通用代码的大机构,他们 应改为被认为是一种技术,以保证代码 小区域的执行。

+0

这看起来像是一个bug,Abort()被忽略。发布到connect.microsoft.com –

回答

7

的问题是,你正在试图中止线程在catch子句中运行。

这将中止该线程:

static void Main(string[] args) { 
    var thread = new Thread(() => { 
    Thread.Sleep(Timeout.Infinite); 
    }); 
    thread.Start(); 

    Thread.Sleep(TimeSpan.FromSeconds(1)); 

    thread.Abort(); 
    thread.Join(); 
} 

this article

在.NET Framework 2.0中,CLR延迟优美的线程在核证减排量,finally块,catch块中止在默认情况下,静态构造函数和非托管代码。

这一特征的存在是为了保持.NET框架中的某些异步异常的脸更可靠。阅读我为完整故事链接的文章。

你的代码基本上行为不检和主机可能会加剧该线程一个粗鲁的线程中止:

粗鲁的线程中止和粗鲁的应用程序域卸载使用由CLR主机,以确保失控的代码可以保持在检查。当然,由于这些操作导致终结器或非CER终止块失败,这给CLR主机带来了新的可靠性问题,因为这些操作很可能会泄露退出代码应该清理的资源。

+0

其实我知道。我问为什么它的工作方式 – karabara

+0

增加了一些解释.... –

1

嫌疑的一点是,当你在一个catch或finally块,你可能想后自己清理了。如果在这一点上可以触发异步异常,那么执行任何可靠的清理都将非常困难。

乔·达菲的blog post about asynchronous exceptions很可能会澄清这比我更多...

+0

它在finally块中的Abort()调用块中工作。不在catch块中,这是错误。 –

+0

@Hans它只是说它*可能*阻止。在异常处于活动状态的finally块中,可能存在与catch块相同的问题。 –

+0

此链接已死亡。 –

1

这是由设计,这是外汇引进3或4
你可以看一下不同的版本形成了你自己的链接,找到不同的描述。

允许那些保护区域内的AbortException(如Fx的1.x中)可能导致非常不可预见的情况而不稳定的过程。

注意Thread.Abort()是(为)一般DIS-建议。任何catch或finally子句中的长时间运行的代码也是如此。

禁止中止中断catch子句可解决Abort的一些问题。但它仍然不完美。