【问题标题】:.NET - Finalizers and exit(0).NET - 终结器和退出 (0)
【发布时间】:2009-04-03 13:03:30
【问题描述】:

我有一个 .NET C#/C++ 应用程序,它在线程中使用对 exit(0)(来自 <stdlib.h>)的调用来终止。

奇怪的是,在某些情况下,托管对象的终结器在调用 exit 之后立即被调用,而在其他情况下,它们根本不会被调用。

情况非常确定 - 应用在其生命周期内从外部插件 dll(用非托管 C 编写)调用一些方法。
如果我使用 dll A,则始终调用终结器。
如果我使用 dll B,则永远不会调用终结器。

在调用 exit(0) 的情况下,终结器的预期行为是什么? (如果有任何预期的 - 和记录的 - 行为)

对外部 dll 的调用能否更改一些可能影响进程终止方式的全局设置?

【问题讨论】:

  • 您可能应该使用 IDisposable 模式而不是终结器。
  • 我也想过,第一次看到代码的时候,但邪恶已经存在,在代码库中……

标签: c# .net c++ finalizer object-lifetime


【解决方案1】:

Chris Brumme 谈到了在进程关闭期间如何处理终结器:

最重要的是,对于终结器在关闭时运行的保证似乎很少,但我不确定 DLL 可能会做什么来导致事情发生不同(也许就是那个) DLL 在 DLL_PROCESS_DETACH 处理中做一些事情,这让 .NET 有机会处理终结器。

这篇文章适用于 .NET 1.x - 我不确定在 .NET 2.0 或更高版本中有多少变化。

【讨论】:

    【解决方案2】:

    根据 Jeff Richter 的书,系统确实会在进程关闭时尝试调用终结器,但在此过程中同时存在每个终结器 (2s) 和总终结器 (40s) 超时,之后进程中止. (当然,确切的时间现在可能已经改变了,这对 2.0 来说是正确的)

    您会看到运行时间超过 2 秒的终结器吗?这将导致最终确定停止。

    【讨论】:

    • 我也有这本书(第 3 版)是哪一页写的?
    【解决方案3】:

    归根结底,这是一个“军备竞赛”问题。有人在微软记录了一个错误,抱怨当一些讨厌的代码使进程退出时,他们的终结器没有运行——因此问题得到了解决。然后其他人记录了一个关于似乎没有办法强制进程立即退出以使终结器不运行的错误,因此微软添加了一个新的 API 来再次允许它。因此,另一个人需要一种新的“关键”终结器,即使响应这种新的退出,它也始终运行......等等。

    因此,更改 C++ 代码可能比尝试依赖当前赢得军备竞赛的人更容易。

    【讨论】:

    • TerminateProcess(GetCurrentProcess()) 保证不会运行终结器或倒回堆栈(这些是本机方法 -- P/Invoke 它们两者)。
    【解决方案4】:

    如果您放入终结器中的代码相当关键,请将其移至 Dispose 并在 Dispose 中使用 if( !disposed ) 模式在终结器中调用 Dispose。

    在我的书中,不应该依赖终结器来被运行时调用。 Dispose 是显式的,您可以对其进行更精细和确定性的控制。

    【讨论】:

      猜你喜欢
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2015-05-30
      • 2018-09-12
      • 1970-01-01
      相关资源
      最近更新 更多