信号的捕获和处理
信号(signal)是在特定事件发生时由操作系统向进程发送的消息。它一种软件中断,是进程间唯一的异步通信方式。
信号有很多,常见的有:
SIGINT:在键盘按下<Ctrl+C>组合键后产生,默认动作为终止进程
SIGQUIT:在键盘按下<Ctrl+\>组合键后产生,默认动作为终止进程
SIGKILL:无条件终止进程。本信号不能被忽略、处理和阻塞。默认动作为终止进程。它向系统管理员提供了一种可以杀死任何进程的方法
SIGALRM:定时器超时,超时的时间由系统调用alarm设置。默认动作为终止进程
SIGCHLD:子进程终止或者停止的时候,父进程会收到这个信号。默认动作为忽略该信号
信号的捕捉和处理
信号的捕捉和处理由以下2个函数来完成,其中第一个函数也是由第二个函数实现的:
#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数signum指定信号的种类,比如SIGINT、SIGKILL等。
参数handler是一个函数指针,指定捕捉到该信号后的处理函数。
signal函数执行成功时返回信号处理函数指针,发生错误时返回SIG_ERR。
sigaction函数类似于signal函数,而且它完全可以替代后者,也更稳定。之所以稳定,是signal函数在UNIX系列的不同操作系统中可能存在区别,但sigaction函数完全相同。实际上现在很少用signal函数来编写程序,它只是为了保持对旧程序的兼容。
1. signal()函数
#include <stdio.h>
#include <signal.h>
/*信号处理函数*/
void handler_sigint(int signo)
{
printf("recv SIGINT\n");
}
int main()
{
/*安装信号处理函数*/
signal(SIGINT, handler_sigint);
while(1)
;
return 0;
}
程序使用signal()安装SIGINT的处理函数handler_sigint,然后进入无限循环。当接收到SIGINT信号时,程序自动跳转到信号处理函数处执行,打印出提示信息。然后返回主函数继续无限循环。执行结果如下:
2. sigaction()函数
sigaction函数中用到了一个结构体sigaction作为参数。此结构体中的字段常用的有2个,sa_handler用来指定信号发生后的处理函数,sa_flags用来进行一些设定。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int temp = 0;
/*信号处理函数*/
void handler_sigint(int signo)
{
printf("recv SIGINT\n");
sleep(5);
temp += 1;
printf("the value of temp is: %d\n", temp);
printf("in handler_sigint, after sleep\n");
}
int main()
{
struct sigaction act;
/*赋值act结构*/
act.sa_handler = handler_sigint;
act.sa_flags = SA_NOMASK; //此设置意味着,对于可靠信号,发生了多少次,就调用信号处理函数多少次,即信号不会丢失
/*安装信号处理函数*/
sigaction(SIGINT, &act, NULL);
while(1)
;
return 0;
}
运行上述程序后,在键盘上快速按下5次<Ctrl+C>组合键,屏幕上会连续打印出5行提示消息。在休眠5秒后,再将临时变量temp的值依次打印出来。这是由于设定了sa_flags的值为SA_NOMASK,因此程序能够反复响应信号SIGINT,程序从sleep()处嵌套调用信号处理函数handler_sigint,多次打印出“recv SIGINT”。睡眠5秒后,将temp的值打印出来并返回到本次信号处理程序的跳入点sleep()处,最后返回到主函数。