我有一个程序必须在完成之前执行某些任务。问题是有时程序崩溃时会出现异常(如无法访问数据库等)。 现在,有没有办法检测异常终止并在它死之前执行一些代码?
感谢。
代码表示赞赏。
答案 0 :(得分: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()获取回溯以查看导致信号的原因。
答案 1 :(得分:5)
有sysinternals forum threads关于通过挂钩NT Internals来防止最终进程尝试,但你真正想要的是监视器或对等进程(合理的方法)或某种拦截灾难性事件的方法(非常冒险)。
编辑:有理由说他们为什么会这么做,但是有可能拦截或阻止企图杀死你的进程。我知道你只是在退出之前试图清理,但是一旦有人发布了一个无法立即杀死的进程,有人会要求立即杀死它的方法,等等。无论如何,要走这条路,看看上面链接的线程,并搜索你在那里找到的一些关键字更多。 hook OR过滤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 / __换行。无论如何,在文章"SetUnhandledExceptionFilter" and VC8中有一些示例代码和过滤对SetUnhandledExceptionFilter的调用的讨论。
另外,有关 AddVectoredExceptionHandler 的示例代码,请参阅The Awesome Factor的Windows SEH Revisited。
答案 2 :(得分:2)
这取决于你对“例外”做了什么。如果你正确处理它们并退出程序,你可以使用atexit()
注册退出时调用的函数。
如果发生真正的异常终止,它将不起作用,例如segfault。
不了解Windows,但在POSIX兼容的操作系统上,您可以安装信号处理程序,捕获不同的信号并对其进行一些操作。当然,你无法抓住SIGKILL
和SIGSTOP
。
自C89以来,Signal API是ANSI C的一部分,因此Windows可能支持它。有关详细信息,请参阅signal()
系统调用。
答案 3 :(得分:1)
如果它只是Windows,那么您可以使用SEH(SetUnhandledExceptionFilter)或VEH(AddVectoredExceptionHandler,但它仅适用于XP / 2003及以上版本)
答案 4 :(得分:0)
抱歉,不是Windows程序员。但也许
_onexit()
注册程序终止时要调用的函数。
http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx
答案 5 :(得分:0)
首先,虽然这是相当明显的:你永远不会有一个完全强大的解决方案 - 总有人可以直接用电源线来终止你的过程。所以你需要妥协,你需要仔细列出妥协的细节。
更强大的解决方案之一是将相关代码放在包装器程序中。包装程序调用您的“真实”程序,等待其进程终止,然后 - 除非您的“真实”程序明确表示它已正常完成 - 运行清理代码。对于像测试工具这样的东西来说,这是很常见的,测试程序可能会崩溃或中止或以其他方式死亡。
如果有人在您的包装函数上执行TerminateProcess,那么仍然会给您带来困难,如果这是您需要担心的事情。如果有必要,您可以通过在Windows中将其设置为服务并使用操作系统的功能在其停止时重新启动它来解决这个问题。 (这只会改变一些事情;有些人仍然可以停止服务。)此时,您可能正处于需要通过持久性创建文件来表示成功完成的位置。
答案 6 :(得分:0)
几年前我在ddj.com上发表了一篇关于“事后调试”的文章。
它包含windows和unix / linux的源代码,用于检测异常终止。根据我的经验,使用SetUnhandledExceptionFilter安装的Windows处理程序并不总是被调用。在许多情况下,它被调用,但我从客户那里收到了很多日志文件,这些日志文件中没有包含安装处理程序的报告,其中就是访问违规行为。