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