检测程序终止(C,Windows)

问题描述:

我有一个程序在完成之前必须执行某些任务。问题是,有时程序崩溃,例外(如数据库无法到达等)。 现在,有没有什么方法可以检测到异常终止并在它死前执行一些代码?检测程序终止(C,Windows)

谢谢。

代码表示赞赏。

+0

使用SIGSEGV信号处理程序。 ;-) – 2009-09-09 15:39:03

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()进行回溯以查看造成信号的原因。

+4

另外,关于你对TerminateProcess()的评论......简单的答案是你不能在为你的进程调用TerminateProcess()之后做任何事情。不要过关,不要收200美元。你的程序现在退出。期。结束。 – cigarman 2009-09-09 15:31:11

+0

感谢您的意见。问题不是例外。问题是检测到崩溃或终止呼叫。 我可以处理的异常 – wonderer 2009-09-09 17:02:17

+0

这就是SetUnhandledExceptionFilter所做的,它处理像栈溢出,空内存访问等“崩溃”。它不仅仅是try/catch意义上的异常处理程序。 – cigarman 2009-09-09 18:28:30

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

+0

我认为这可能有帮助。你有一个样本片段? – wonderer 2009-09-08 14:36:45

+0

http://codepad.org/mUAUB25D - 但这是最​​简单的一种,网络上有更复杂的崩溃处理程序(例如,在CodeProject上)。 – 2009-09-08 14:55:06

+0

我试过了,它看起来不错,但是如果我杀死了进程(来自任务管理器等),它不会检测到它。 – wonderer 2009-09-08 17:34:24

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

如果发生真正的异常终止,就像segfault一样,它将不起作用。

不知道Windows,但是在符合POSIX标准的操作系统上,您可以安装信号处理程序,它可以捕获不同的信号并对其进行处理。当然,你不能赶上SIGKILLSIGSTOP

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

+0

是的...我需要能够检测到一个正常和异常终止... – wonderer 2009-09-08 17:33:39

+0

我使用类似的东西赶上ctrl-c和其他终止信号,但我无法捕捉TerminateProcess。 如果我没有记错,你不能停止一个SIGKILL,这同样适用于TerminateProcess。它只是导致应用程序死亡。 – wonderer 2009-09-09 12:54:58

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

_onexit() 

注册一个函数,当程序终止时被调用。

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

+0

这是C++,而不是C. – 2009-09-08 14:43:39

+0

谢谢,但它并没有真正的帮助。我可以赶上正常的终止。 – wonderer 2009-09-08 14:46:08

首先,虽然这是相当明显的:你永远不能拥有一个完全可靠的解决方案 - 某人总能正好砸在电力电缆终止您的进程。所以你需要妥协,你需要仔细地阐述妥协的细节。

其中一个更强大的解决方案是将相关代码放入包装程序中。包装程序调用您的“真实”程序,等待其进程终止,然后 - 除非您的“真实”程序明确表示它已正常完成 - 运行清理代码。对于像测试线束这样的测试程序可能会崩溃或中止或以其他意外方式死亡的情况而言,这是相当常见的。

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

+0

我同意你的意见。我的主要问题是在死于TerminateProcess或其他不可预见的事件之前执行最后一个动作。 其余的事情都照顾好了。 我与负责该项目的负责人讨论了如何将监控应用程序转换为服务,但这不是。 我想没有办法做到这一点... – wonderer 2009-09-09 12:52:08

sysinternals forum threads关于通过挂钩NT内部结构来防止结束进程尝试,但是你真正想要的是监视程序或对等进程(合理的方法)还是拦截灾难性事件(相当危险)的某种方法。

编辑:他们为什么要这么做很困难,但可以拦截或阻止企图杀死你的进程。我知道你只是在退出前试图清理,但只要有人释放了一个无法立即杀死的进程,就会有人要求立即杀死它的方法,等等。无论如何,要走这条路,请参阅上面的链接线索并搜索一些您在其中找到的关键字以获取更多信息。 hook或过滤器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回调函数应用程序定义用于将数据和应用程序状态信息保存在事件的应用程序的回调函数遇到一个未处理的异常或无响应。

使用SetUnhandledExceptionFilterMSDN Social discussion建议,使这项工作可靠,修补方法是在内存中是要确保你的过滤器会被调用的唯一途径。建议用__try/__除外。无论如何,在文章"SetUnhandledExceptionFilter" and VC8中有一些示例代码和过滤对SetUnhandledExceptionFilter的调用的讨论。

另外,请参阅The Awesome Factor中的Windows SEH Revisited,以获得AddVectoredExceptionHandler的一些示例代码。

+0

谢谢。我以前看过那些。有2个问题,tho。 1)我必须支持XP。 2)我不需要从崩溃中恢复。我只需要在关闭应用程序之前保存几个文件并关闭数据库连接(正常或崩溃之前)。 – wonderer 2009-09-09 12:48:50

+0

Gotcha。增加了关于SUEF和AVEH示例代码和讨论的一些信息和链接。 – 2009-09-09 15:27:34

+0

让我试试这个。不过,我无法捕捉到TerminateProcess。从我所看到的这是不可能的 – wonderer 2009-09-09 17:05:58

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

它包括Windows和Unix/Linux的来源来检测异常终止。根据我的经验,使用SetUnhandledExceptionFilter安装的窗口句柄是并不总是调用。在很多情况下,它被调用,但我收到了不少来自客户的日志文件,这些日志文件中没有包含来自已安装处理程序的报告,这是因为访问违规是原因。

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

+0

谢谢。我的问题是热的例外。 – wonderer 2009-09-09 17:03:29