【发布时间】:2010-11-26 12:38:03
【问题描述】:
我有一个程序必须在完成之前执行某些任务。问题是有时程序会因异常而崩溃(例如无法访问数据库等)。 现在,有什么方法可以检测异常终止并在它死之前执行一些代码?
谢谢。
代码表示赞赏。
【问题讨论】:
-
使用 SIGSEGV 信号处理程序。 ;-)
标签: c windows process termination
我有一个程序必须在完成之前执行某些任务。问题是有时程序会因异常而崩溃(例如无法访问数据库等)。 现在,有什么方法可以检测异常终止并在它死之前执行一些代码?
谢谢。
代码表示赞赏。
【问题讨论】:
标签: c windows process termination
几年前,我在 ddj.com 上发表了一篇关于“事后调试”的文章。
它包括用于检测异常终止的 windows 和 unix/linux 的源代码。不过,根据我的经验,使用 SetUnhandledExceptionFilter 安装的 Windows 处理程序并不总是被调用。在许多情况下,它被调用,但我从客户那里收到不少日志文件,其中不包括来自已安装处理程序的报告,即访问违规是原因。
【讨论】:
sysinternals forum threads 关于通过挂钩 NT Internals 来防止终端进程尝试,但您真正想要的是看门狗或对等进程(合理的方法)或某种拦截灾难性事件的方法(相当冒险)。
编辑:它们使这变得困难是有原因的,但是可以拦截或阻止杀死您的进程的尝试。我知道你只是想在退出前清理一下,但是一旦有人释放了一个不能立即杀死的进程,就会有人要求立即杀死它的方法,以此类推。无论如何,要走这条路,请参阅上面的链接线程并搜索您在其中找到的一些关键字以获取更多信息。 hook OR filter NtTerminateProcess 等等。我们在这里讨论内核代码、设备驱动程序、防病毒、安全、恶意软件、rootkit 的东西。在这方面有帮助的一些书籍是Windows NT/2000 Native API、Undocumented Windows 2000 Secrets: A Programmer's Cookbook、Rootkits: Subverting the Windows Kernel,当然还有Windows® Internals: Fifth Edition。这些东西编写起来并不难,但要恰到好处却很棘手,而且您可能会引入意想不到的副作用。
也许Application Recovery and Restart Functions 有用吗?受 Vista 和 Server 2008 及更高版本支持。
ApplicationRecoveryCallback 回调函数 应用程序定义的回调函数,用于在应用程序遇到未处理的异常或无响应时保存数据和应用程序状态信息。
在使用 SetUnhandledExceptionFilter 时,MSDN Social discussion 建议要使这项工作可靠,在内存中修补该方法是确保调用过滤器的唯一方法。建议改为使用 __try/__except 进行包装。不管怎样,文章"SetUnhandledExceptionFilter" and VC8 中有一些示例代码和过滤调用 SetUnhandledExceptionFilter 的讨论。
另外,有关 AddVectoredExceptionHandler 的一些示例代码,请参阅 The Awesome Factor 的 Windows SEH Revisited。
【讨论】:
1. Win32
Win32 API 包含一种通过SetUnhandledExceptionFilter 函数执行此操作的方法,如下所示:
LONG myFunc(LPEXCEPTION_POINTERS p)
{
printf("Exception!!!\n");
return EXCEPTION_EXECUTE_HANDLER;
}
int main()
{
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&myFunc);
// generate an exception !
int x = 0;
int y = 1/x;
return 0;
}
2。 POSIX/Linux
我通常通过signal() 函数执行此操作,然后适当地处理 SIGSEGV 信号。您还可以处理 SIGTERM 信号和 SIGINT,但不能处理 SIGKILL(按设计)。您可以使用strace() 进行回溯以查看导致信号的原因。
【讨论】:
这取决于您如何处理“例外”。如果您正确处理它们并退出程序,则可以使用atexit() 注册要在退出时调用的函数。
在真正异常终止的情况下不起作用,例如segfault。
不了解 Windows,但在兼容 POSIX 的操作系统上,您可以安装信号处理程序,该处理程序将捕获不同的信号并对其进行处理。当然你抓不到SIGKILL和SIGSTOP。
自 C89 以来,信号 API 是 ANSI C 的一部分,因此 Windows 可能支持它。有关详细信息,请参阅signal() 系统调用。
【讨论】:
首先,尽管这很明显:您永远不可能有一个完全可靠的解决方案——有人总是可以通过敲击电源线来终止您的进程。所以你需要妥协,并且你需要仔细列出妥协的细节。
其中一个更强大的解决方案是将相关代码放入包装程序中。包装程序调用你的“真实”程序,等待它的进程终止,然后——除非你的“真实”程序明确表示它已经正常完成——运行清理代码。这对于测试工具之类的事情相当普遍,因为测试程序可能会崩溃或中止或以其他方式以意想不到的方式死亡。
如果有人在你的包装函数上执行 TerminateProcess 会发生什么,这仍然会给你带来困难,如果这是你需要担心的事情。如有必要,您可以通过在 Windows 中将其设置为服务并使用操作系统的功能在其死机时重新启动它来解决此问题。 (这只是稍微改变了一些事情;仍然有人可以停止服务。)此时,您可能正处于需要通过诸如创建文件之类的持久性事物来表示成功完成的地步。
【讨论】:
对不起,不是 Windows 程序员。但也许
_onexit()
注册一个在程序终止时调用的函数。
http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx
【讨论】:
如果它仅适用于 Windows,那么您可以使用 SEH (SetUnhandledExceptionFilter) 或 VEH (AddVectoredExceptionHandler,但它仅适用于 XP/2003 及更高版本)
【讨论】: