我有一个使用其他人服务的程序。如果程序崩溃,关闭这些服务的最佳方法是什么?在服务器端,我会定义一些检查程序,监视客户端是否定期无效。但我们可以在客户端做任何事情吗?如果正常的RAII在这种情况下仍能正常工作,我不确定。我的代码是用C和C ++编写的。
答案 0 :(得分:6)
如果您的应用程序遇到严重崩溃,那么不会,您的精心设计的清理代码将无法运行,无论它是RAII范例的一部分还是您在main
结束时调用的方法。在导致应用程序终止的崩溃后,应用程序的清理代码都没有运行。
当然,例外并非如此。虽然这些可能最终导致应用程序终止,但它们仍然以受控方式触发此终止。通常,运行时库将捕获未处理的异常并触发终止。在此过程中,将执行基于RAII的清理代码,除非它也抛出异常。然后你又回到了毫不客气地被撕掉的记忆。
但即使您的应用程序清理代码无法运行,操作系统仍会尝试在您之后进行清理。这解决了未释放的内存,句柄和其他系统对象的问题。一般来说,如果你崩溃了,你不必担心发布这些东西。您的应用程序状态不一致,因此尝试执行一堆清理代码只会导致不可预测且可能出现错误的行为,更不用说浪费大量时间了。只是崩溃,让系统处理你的烂摊子。 As Raymond Chen puts it:
该建筑正在拆除。不要打扰地板,清空垃圾桶,擦掉白板。并且不要在建筑物的出口处排队,这样每个人都可以将他们的进/出磁铁移出。你所做的只是让拆迁队等你完成这些毫无意义的清理工作。
做你必须做的事;跳过其他一切。
这种方法的唯一问题是,正如您在此问题中所建议的那样,当您管理不受操作系统控制的资源时,例如另一个系统上的远程资源。在这种情况下,你可以做的很少。 最佳方案是让您的应用程序尽可能健壮,这样它就不会崩溃,但即使这样也不是一个完美的解决方案。考虑当电源丢失时会发生什么,例如,因为用户的猫从墙上拔下了电线。因此,可能无法运行清理代码,因此即使您的应用程序永远不会崩溃,也可能存在超出您控制范围的终止事件。因此,您的外部资源必须在发生故障时才能保持健壮。超时是一种标准方法,也是一种比民意测验更好的解决方案。
根据具体的使用案例,另一种可能的解决方案是在应用程序初始化中运行一致性检查和清理代码。这可能是您要为连续运行的服务所做的事情,并将在终止后立即重新启动。下次重新启动时,它会检查其数据和/或外部资源的一致性,发布和/或根据需要重新初始化它们,然后继续正常运行。显然这对于典型应用程序来说是一个糟糕的解决方案,因为无法保证用户会及时重新启动它。
答案 1 :(得分:3)
正如其他答案所表明的那样,希望在不受控制的崩溃之后进行清理(即,没有触发C ++异常展开机制的故障)可能是一条无处可去的路。即使你覆盖了某些案例,也会有其他案例失败,而你正在构建一个严重的案例。
你提到崩溃的根源在于你是"我们来自其他人的服务"。我认为这意味着您正在运行不受信任的代码,这是崩溃的潜在来源。在这种情况下,您可以考虑运行不受信任的代码"进程外"并通过管道或共享内存或其他任何方式与主进程通信。然后,您可以隔离此子进程的崩溃,并可以在主进程中进行受控清理。一个单独的进程实际上是你可以做的最轻量级的事情,它为你提供了避免调用代码中的损坏所需的强大隔离。
如果分支每次调用进程的性能过高,您可以尝试让子进程保持活动状态以进行多次调用。
答案 2 :(得分:1)
一种方法是让您的程序有两种模式:正常操作和监控。
以通常方式启动时,它会:
当使用内部参数启动时,它将:
答案 3 :(得分:-1)
您可以查看atexit
,这可能会为您提供在程序终止时释放资源所需的功能。但我并不相信这是绝对正确的。