如果程序崩溃,如何释放资源

我有一个使用其他人服务的程序。 如果程序崩溃,关闭这些服务的最佳方法是什么? 在服务器端,我会定义一些检查器,监视客户端是否定期无效。 但我们可以在客户端做任何事情吗? 如果正常的RAII在这种情况下仍能正常工作,我不确定。 我的代码是用C和C ++编写的。

如果您的应用程序遇到硬崩溃,那么不会,您的精心设计的清理代码将无法运行,无论它是RAII范例的一部分还是您在main结束时调用的方法。 在导致应用程序终止的崩溃之后, 应用程序的清理代码都不会运行。

当然,例外情况并非如此。 虽然这些可能最终导致应用程序终止,但它们仍然以受控方式触发此终止。 通常,运行时库将捕获未处理的exception并触发终止。 在此过程中,将执行基于RAII的清理代码,除非它也引发exception。 然后你又回到了毫不客气地被撕掉的记忆中。

但即使您的应用程序的清理代码无法运行, 操作系统仍会尝试在您之后进行清理。 这解决了未释放的内存,句柄和其他系统对象的问题。 一般来说,如果你崩溃了,你不必担心发布这些东西。 您的应用程序的状态不一致,因此尝试执行一堆清理代码只会导致不可预测且可能出现错误的行为,更不用说浪费大量时间了。 只是崩溃,让系统处理你的烂摊子。 正如Raymond Chen所说 :

该建筑正在拆除。 不要费心扫地,清空垃圾桶,擦掉白板。 并且不要在建筑物的出口排队,这样每个人都可以将他们的进/出磁铁移出。 你所做的只是让拆迁队等你完成这些毫无意义的清理工作。

做你必须做的事; 跳过其他一切。

这种方法的唯一问题是,正如您在此问题中所建议的那样,当您管理不受操作系统控制的资源时,例如另一个系统上的远程资源。 在那种情况下,你几乎无能为力。 最好的方案是让你的应用程序尽可能健壮,这样它就不会崩溃,但即便这样也不是一个完美的解决方案。 考虑当电源丢失时会发生什么, 例如因为用户的猫从墙上拉下了电线。 然后,可能无法运行清理代码,因此即使您的应用程序永远不会崩溃,也可能存在超出您控制范围的终止事件。 因此,在发生故障时,您的外部资源必须是健壮的。 超时是一种标准方法,是一种比轮询更好的解决方案。

根据具体的使用情况,另一种可能的解决方案是在应用程序初始化时运行一致性检查和清理代码。 这可能是您要为连续运行的服务所做的事情,并将在终止后立即重新启动。 下次重新启动时,它会检查其数据和/或外部资源的一致性,发布和/或根据需要重新初始化它们,然后继续正常运行。 显然,这对于典型应用程序来说是一个糟糕的解决方案,因为无法保证用户会及时重新启动它。

正如其他答案所表明的那样,希望在不受控制的崩溃之后进行清理(即,不会触发C ++exception展开机制的故障)可能是一条无处可寻的路径。 即使你覆盖了某些案例,也会有其他案例失败,而你正在构建一个严重的漏洞。

你提到崩溃的根源在于你是“我们来自他人的服务”。 我认为这意味着您正在运行不受信任的代码,这是崩溃的潜在来源。 在这种情况下,您可以考虑运行不受信任的代码“进程外”并通过管道或共享内存或其他任何方式与主进程通信。 然后,您可以隔离此子进程的崩溃,并可以在主进程中进行受控清理。 一个单独的进程实际上是您可以做的最轻量级的事情,它为您提供了避免调用代码中的损坏所需的强大隔离。

如果分支每次调用进程的性能过高,则可以尝试使子进程保持活动状态以进行多次调用。

一种方法是让您的程序有两种模式:正常操作和监视。

当以通常的方式启动时,它会:

  1. 充当背景监视器。
  2. 启动它自己的子进程,传递一个内部参数(不会与传递给它的普通参数冲突,如果有的话)。
  3. 当子进程存在时,它将释放服务器上保存的所有资源。

当使用内部参数启动时,它会:

  1. 使用服务器的资源公开用户界面并“正常行动”。

您可以查看atexit ,它可以为您提供在程序终止时释放资源所需的function。 不过,我不相信这是绝对正确的。

但话说回来,你应该专注于确保你的程序不崩溃; 如果您遇到“不可恢复”的错误,您仍应投入一些error handling代码。 如果错误是由Seg-Fault或其他类似的OS相关错误引起的,您可以启用SEHexception(不确定这是否是特定于Windows的)以使您能够使用正常的try-catch块捕获它们,或写一些信号处理程序来拦截这些错误并处理它们。