【问题标题】:How to handle AppDomain.Unload and the related ThreadAbortException如何处理 AppDomain.Unload 和相关的 ThreadAbortException
【发布时间】:2012-02-23 15:31:55
【问题描述】:

根据 MSDN,AppDomain.Unload 会导致卸载 AppDomain 内的所有线程抛出线程中止异常。

域中的线程使用 Abort 方法终止,该方法 在线程中引发 ThreadAbortException。虽然线程 应立即终止,它可以继续执行一个 finally 子句中不可预测的时间量。 -- 来自MSDN

所以我的理解是,每当我在任何地方编写预期在此 AppDomain 中运行的代码时,我都必须预料到任何线程都可能随时发生线程中止。这是真的? 是否所有代码都应该假设可以随时抛出 ThreadAbortException?

实际上这实际上消除了 catch(Exception ex),因为它会捕获 ThreadAbortException 并尝试处理它,通常是通过记录一个确实不应该记录的错误(因为卸载 AppDomain 是' t真的是一个例外)。

为了避免不必要的异常处理/错误记录,是否还有其他需要注意的事项?

【问题讨论】:

  • 我已经经历了 很多 明确“不缓存”ThreadAbort(甚至 OutOfMemory..)的代码。如果将“系统关键”异常与其他异常分开应该会很好,但没有:}
  • 谢天谢地,至少 ThreadAbort 需要显式重置才能不重新抛出(因此“捕获”它主要是错误记录/无效恢复/错误假设程序保持在有效状态的问题) ; OOM 有时会被扼杀,直到 .NET 进程“致命”崩溃:}

标签: c# .net appdomain threadabortexception


【解决方案1】:

对于任何时候 TAE 的可能性,您几乎都抱有正确的期望。我要说的唯一一点是,您的代码可能应该已经以这种方式编写了-在处理具有可靠性要求的数据时,您应该在硬件故障、操作员错误、OOM 等情况下使用事务或其他补偿机制-任何其中并非 AppDomain 关闭场景独有。

最后,您应该知道您可以捕获 TAE 并在 catch 块中执行补偿代码。它们唯一的特别之处是它们会在 catch 块之后立即被重新抛出,所以你不能“吞下”它们。您可以使用Thread.ResetAbort() 来抑制它们,但在这种情况下,这可能不是您想要的效果。

我们都写过这样的代码:

public void Foo() {
    try {
        Do.Some.Stuff();
    } catch (Exception ex) {
       Console.Out.WriteLine("Oh noes!");
    }
}

是的,catch 块将捕获所有内容1,包括 TAE 和 OOM。

这里要记住的是,对于上述所有例外情况,世界基本上都在结束。您应该关心的是,您正在处理的任何事务敏感数据都不会丢失或处于不良状态,这就是为什么我们通常将事务安全 I/O 之类的事情留给 Microsoft 和 Oracle 的聪明人谁写数据库。例如,如果您的代码正在执行平面文件 I/O,您需要非常确定永远不会使文件处于错误状态,那么您应该以非常全面的方式考虑故障模式- 比如“如果这个文件写到一半就断电了怎么办?”

1 唯一的例外是StackOverflow exceptions generally cannot be caught。这是 .NET 2.0 中的一个变化。

【讨论】:

  • 好答案,也许您应该补充一点:您应该正确实现 IDisposable 模式,包括您正在使用的每个非托管资源的对象终结器部分。如果您正在使用互斥锁,这是避免系统范围锁定的唯一方法。当抛出 ThreadAbortException 时,最终块和对象终结器无论如何都会运行,这可以节省您的时间。我听起来很害怕吗? 我是
  • 一个小修正。据我了解,您无法在 .Net 2 或更高版本上捕获 StackOverflowException。自己试试看MSDN
【解决方案2】:

您无法处理ThreadAbortException,因此无需捕获异常。更专业的

是一个特殊的异常,可以被捕获,但是它会自动 在 catch 块的末尾再次提升

来自here

【讨论】:

  • 是否所有代码都应该假设可以随时抛出 ThreadAbortException?此外,这是否实际上消除了 catch(Exception ex),因为它将处理 ThreadAbortException?在我的问题中,我的意思不是句柄,而是在一般情况下,我们应该如何编码知道可以随时在任何线程上抛出 threadabortexception
  • 任何你做的和需要自己清理的工作都必须使用 dispose 模式和可能的事务。然而,大多数代码不需要那个。
  • 实际上,您可以通过在 catch 块中发出 Thread.ResetAbort() 来捕获 ThreadAbortException
  • 1) 代码可以 捕获(甚至没有 抑制a) 线程中止的传播 2) 有时会触发[用户] 线程中止在程序集卸载之外..所以这个答案显然是不正确的,即使一个人经常“不应该”来自应用程序级代码。在较低级别的代码(.NET 库中有很多示例)中,处理异步 ThreadAbort / OOM 异常的案例值得注意。
猜你喜欢
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 2023-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多