我有一个使用套接字,数据库连接等的进程。它基本上是在传感器数据和Web界面之间进行中继的服务器进程,因此确保应用程序(如果被杀死)正常终止是很重要的。
我如何处理意外的异常,例如段错误(至少用于调试)以及杀死信号,以便我可以关闭任何连接并停止任何线程运行,以便进程不会留下任何正在使用的东西?
您安装信号处理程序以捕获信号 - 但是在99%的情况下您只想退出并让Linux操作系统负责清理 - 它将很乐意关闭所有文件,套接字,空闲内存和关闭线程。
因此,除非你想要做任何具体的事情,比如在套接字上发送消息,那么你应该退出进程而不是试图捕获信号。
捕获信号很难。你必须要小心。您的第一步是使用sigaction
为所需信号安装信号处理程序。
SIGTERM
退出,SIGHUP
重新启动,SIGUSR1
重新加载配置等。SIGKILL
无法被抓住。除非你有充分的理由,否则不应该抓住SIGSEGV
,SIGBUS
和其他类似的人。如果你想调试,那么提高核心转储的ulimit - 将调试器附加到核心映像比你或我编写的任何代码都要有效得多。 (如果你确实尝试在SIGSEGV
或类似之后进行清理,请意识到清理代码可能会导致额外的SIGSEGV
并且事情可能会很快变坏。只要避免整个混乱,让SIGSEGV
终止你的程序。)select
或poll
),那么信号处理程序只需设置一个标志或将一个字节写入一个特殊的管道,以通知主循环退出。你也可以使用siglongjmp
跳出一个信号处理程序,但这很难正确,通常不是你想要的。在不知道应用程序的结构和功能的情况下,很难推荐一些东西。
还记得信号处理程序本身几乎什么都不做。从信号处理程序调用许多函数是不安全的。
我有时喜欢在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();
}
}
你确实要小心处理这些事情,例如:确保你不能触发另一个信号。