9

我有一个程序必须在完成之前执行某些任务。问题是有时程序会因异常而崩溃(例如无法访问数据库等)。现在,有没有办法检测异常终止并在它死之前执行一些代码?

谢谢。

代码表示赞赏。

4

7 回答 7

9

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()获取回溯以查看导致信号的原因。

于 2009-09-09T15:26:24.013 回答
5

sysinternals 论坛线程关于通过挂钩 NT Internals 来防止终端进程尝试,但您真正想要的是看门狗或对等进程(合理的方法)或某种拦截灾难性事件的方法(相当冒险)。

编辑:他们让这变得困难是有原因的,但可以拦截或阻止试图杀死你的进程。我知道你只是想在退出前清理一下,但是一旦有人释放了一个不能立即杀死的进程,就会有人要求立即杀死它的方法,以此类推。无论如何,要走这条路,请参阅上面的链接线程并搜索您在其中找到的一些关键字以获取更多信息。hook OR filter NtTerminateProcess等。我们在这里讨论内核代码、设备驱动程序、防病毒、安全性、恶意软件、rootkit 的东西。在这方面有帮助的一些书籍是Windows NT/2000 Native API未记录的 Windows 2000 秘密:程序员的食谱Rootkits:颠覆 Windows 内核,当然还有Windows® Internals:第五版。这些东西编写起来并不难,但要恰到好处却很棘手,而且您可能会引入意想不到的副作用。

也许应用程序恢复和重启功能可能有用?Vista 和 Server 2008 及更高版本支持。

ApplicationRecoveryCallback 回调函数应用程序定义的回调函数,用于在应用程序遇到未处理的异常或变得无响应时保存数据和应用程序状态信息。

在使用SetUnhandledExceptionFilter时,MSDN 社交讨论建议要使这项工作可靠,在内存中修补该方法是确保调用过滤器的唯一方法。建议改为使用 __try/__except 进行包装。无论如何,在文章“SetUnhandledExceptionFilter”和 VC8中有一些示例代码和对 SetUnhandledExceptionFilter 调用过滤的讨论。

此外,有关AddVectoredExceptionHandler的一些示例代码,请参阅 The Awesome Factor 中的Windows SEH Revisited

于 2009-09-09T01:48:30.313 回答
2

这取决于您如何处理“例外”。如果您正确处理它们并退出程序,则可以注册要在退出时调用的函数,使用atexit().

如果发生真正的异常终止,例如段错误,它将不起作用。

不了解 Windows,但在 POSIX 兼容的操作系统上,您可以安装信号处理程序,它将捕获不同的信号并对其进行处理。当然你不能捕捉SIGKILL到 and SIGSTOP

自 C89 以来,Signal API 是 ANSI C 的一部分,因此 Windows 可能支持它。有关详细信息,请参阅signal()系统调用。

于 2009-09-08T14:38:51.583 回答
1

如果它仅适用于 Windows,那么您可以使用 SEH ( SetUnhandledExceptionFilter ) 或 VEH ( AddVectoredExceptionHandler,但它仅适用于 XP/2003 及更高版本)

于 2009-09-08T14:31:55.013 回答
0

几年前,我在 ddj.com 上发表了一篇关于“事后调试”的文章。

它包括用于检测异常终止的 windows 和 unix/linux 的源代码。不过,根据我的经验,并不总是调用使用 SetUnhandledExceptionFilter 安装的 Windows 处理程序。在许多情况下,它被调用,但我从客户那里收到不少日志文件,其中不包括来自已安装处理程序的报告,即访问违规是原因。

http://www.ddj.com/development-tools/185300443

于 2009-09-09T15:37:58.840 回答
0

首先,虽然这是相当明显的:你永远不可能有一个完全强大的解决方案——有人总是可以通过敲击电源线来终止你的进程。所以你需要一个妥协,你需要仔细布置妥协的细节。

更强大的解决方案之一是将相关代码放入包装程序中。包装程序调用你的“真实”程序,等待它的进程终止,然后——除非你的“真实”程序明确表示它已经正常完成——运行清理代码。这对于像测试工具这样的东西来说是相当普遍的,因为测试程序可能会崩溃或中止或以其他方式以意想不到的方式死亡。

如果有人在您的包装器函数上执行 TerminateProcess 会发生什么,这仍然会给您带来困难,如果这是您需要担心的事情。如有必要,您可以通过在 Windows 中将其设置为服务并在其死机时使用操作系统的功能重新启动它来解决此问题。(这只是稍微改变了一些事情;有人仍然可以停止服务。)此时,您可能正处于需要通过诸如创建文件之类的持久性事物来表示成功完成的地步。

于 2009-09-08T23:59:23.943 回答
0

对不起,不是windows程序员。但也许

_onexit()

注册程序终止时要调用的函数。

http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx

于 2009-09-08T14:38:55.080 回答