2011-09-11 47 views
11

Linux下C捕获kill信号我使用套接字,数据库连接和喜欢的过程。它基本上是一个服务器进程,用于在传感器数据和Web界面之间进行中继,因此,确保应用程序(如果遇难​​)优雅地终止非常重要。为正常终止

如何处理意外的异常,如segfaults(至少用于调试)以及杀死信号,以便我可以关闭任何连接并停止任何线程运行,这样进程不会留下任何混乱的使用?

+0

记住继续运行,甚至清理,分段故障后,可能会造成危险。 – icktoofay

+0

'man sigaction' –

+1

另外请记住,你不能捕杀信号。 – Gabe

回答

7

您可以安装信号处理程序来捕获信号 - 但是,只有99%的情况下,您只想退出并让Linux操作系统负责清理工作 - 它会愉快地关闭所有文件,套接字,空闲内存和关闭线程。

所以,除非有什么特别,你想做的事,就像插座发送消息,那么你应该从进程刚刚退出,而不是试图赶上信号。

+0

我认为你就在这里...应用程序的可靠性对我而言更重要,并且做着疯狂的事情信号可能不好。当段错误发生时,如果我得到coredumps,它是否告诉你段错误发生在哪里? – user623879

+0

调用堆栈告诉你是seg-fault发生,假设调用堆栈没有被破坏 - 这里的问题:http://stackoverflow.com/questions/105659/how-can-one-grab-a- stack-trace-in-c讨论如何获得堆栈跟踪 – Soren

+0

伟大的建议。此规则的一个例外是当程序关闭时(在embeeded系统中)需要清理或更改硬件时。 – Havok

6

我有时想获得SIGSEGV回溯,捕捉部分是这样:

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 

void sig_handler(int); 

int main() { 
    signal(SIGSEGV, sig_handler); 
    int *p = NULL; 
    return *p; 
} 

void sig_handler(int sig) { 
    switch (sig) { 
    case SIGSEGV: 
     fprintf(stderr, "give out a backtrace or something...\n"); 
     abort(); 
    default: 
     fprintf(stderr, "wasn't expecting that!\n"); 
     abort(); 
    } 
} 

你要非常小心处理这些事情,例如确保你不能触发另一个信号。

+1

使用'ulimit'来获得核心转储并获得堆栈跟踪更方便吗? –

+0

不熟悉那种方法,你能详细说明一下吗?我只用这个东西来调试btw,即我犯了一个错误,并希望看到信号来自哪里。 – daniel

+2

你真的不应该使用'signal'。多年来,建议不要这样做,而是使用'sigaction'。来自'man signal':* signal()的行为因Unix版本而异,并且在不同版本的Linux中历史上也有所不同。避免使用它:改用sigaction(2)。*。我并不低调......但它很接近。你不应该推荐任何人使用它。 –

10

捕获信号是困难的。你必须要小心。您的第一步是使用sigaction为所需信号安装信号处理程序。

  • 选择一组信号来响应并选择它们对于您的过程意味着什么。例如,SIGTERM退出,重新启动SIGHUPSIGUSR1重新加载配置等

  • 不要试图对所有信号作出反应,也不要试图信号,表示你的程序中的错误后,“清理”。 SIGKILL不能被捕获。 SIGSEGV,SIGBUS,和其他人一样,除非你有很好的理由,否则不应该被抓到。如果你想调试,然后提高核心转储的ulimit - 将调试器附加到核心映像比你或我可以编码的任何东西都要有效得多。 (如果你尝试SIGSEGV或类似的东西清理后,意识到清理代码可能会导致额外的SIGSEGV和事情会变得糟糕的很快,只是避免全乱了,让SIGSEGV终止你的程序。)

  • 你如何处理信号是棘手的。如果您的应用程序有一个主循环(例如,selectpoll),则信号处理程序可以只设置一个标志或字节写入专用管信号的主循环退出。您也可以使用siglongjmp跳出信号处理程序,但这很难正确并且通常不是您想要的。

如果不知道应用程序的结构和功能如何,很难推荐一些东西。

还记得信号处理程序本身应该做的几乎没有。来自信号处理器的许多功能都不安全。