一、前言
信号是一种软件中断(软中断信号),用来通知进程发生了异步事件。在Linux下进程之间可以互相通过系统调用kill发送软中断信号。
一般情况下,对信号的处理可以分为三大类:
1、进程指定信号的处理函数,当接收到该信号时由指定的函数进行处理。
2、忽略信号,即进程接收到信号不做任何处理。
3、由系统默认处理信号,对大部分的信号的缺省操作是使得进程终止。
在实际的应用开发中,可能需要对某些信号进行捕获并自定义处理方法,尤其是系统默认使进程退出的信号,因为有时候需要在程序正常退出或异常退出之前完成某些处理工作,保证程序的可靠性。
因此,我们需要捕获使得程序退出的信号,完成退出处理工作之后,再让程序退出。
二、信号捕获处理和程序退出处理
2.1 信号捕获及处理
- 信号捕获需要用到signal()函数,调用该函数注册一个信号的处理动作。
头文件:#include <signal.h>
函数原型:void (*signal(int sig, void (*func)(int)))(int)
功能:设置某一信号的对应动作
参数:
sig —— 所要处理的信号类型
func —— 描述了与信号关联的动作。一共有三种取值,第一种是自定义的信号处理函数;第二种是SIG_IGN,即忽略信号;第三种是SIG_DFL,即设置系统对信号的默认处理。
- 下面是比较常见的标准信号:
信号 | 描述 |
---|---|
SIGABRT | 由调用abort函数产生,进程非正常退出 |
SIGALRM | 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时 |
SIGBUS | 某种特定的硬件异常,通常由内存访问引起 |
SIGFPE | 数学相关的异常,如被0除,浮点溢出,等等 |
SIGINT | 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 |
SIGPIPE | 在reader中止之后写Pipe的时候发送 |
SIGTERM | 请求中止进程,kill命令缺省发送 |
SIGSEGV | 非法内存访问 |
2.2 程序退出处理
程序退出处理可通过捕获退出事件,注册回调函数进行处理,使用到的是atexit()函数。
头文件:#include <stdlib.h>
函数原型:void atexit(void (*func)(void));
功能:注册终止函数(即main执行结束后调用的函数)。
注意:exit调用这些注册函数的顺序与它们 登记时候的顺序相反。同一个函数如若登记多次,则也会被调用多次。
2.3 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void exitHandle(void);
void sigHandle(int sig);
int main(int argc, char *argv[])
{
//注册回调函数,程序调用 exit 或 mian函数return 或 最后一个线程正常退出时,捕获退出事件,执行退出处理
atexit(exitHandle);
//捕获异常信号,并做相应处理
signal(SIGPIPE, SIG_IGN); //忽略信号
signal(SIGINT, sigHandle); //Ctrl + C
signal(SIGTERM, sigHandle); //kill发出的软件终止
signal(SIGBUS, sigHandle); //总线错误
signal(SIGSEGV, sigHandle); //非法内存访问
signal(SIGFPE, sigHandle); //数学相关的异常,如被0除,浮点溢出等
signal(SIGABRT, sigHandle); //由调用abort函数产生,进程非正常退出
while(1) {
//功能处理...
sleep(1);
}
return 0;
}
//进程退出处理,程序调用 exit 或 main函数return 或 最后一个线程正常退出
void exitHandle(void)
{
//handle
}
//信号处理
void sigHandle(int sig)
{
switch (sig) {
case SIGINT:
printf("*** catch signal : SIGINT, value = %d\n", sig);
break;
case SIGTERM:
printf("*** catch signal : SIGTERM, value = %d\n", sig);
break;
case SIGBUS:
printf("*** catch signal : SIGBUS, value = %d\n", sig);
break;
case SIGSEGV:
printf("*** catch signal : SIGSEGV, value = %d\n", sig);
break;
case SIGFPE:
printf("*** catch signal : SIGFPE, value = %d\n", sig);
break;
case SIGABRT:
printf("*** catch signal : SIGABRT, value = %d\n", sig);
break;
default:
printf("*** catch unknown signal, value = %d\n", sig);
break;
}
exit(0); //调用exit退出程序,会被捕获该事件,从而触发进程退出处理的回调函数
}