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