信号的捕捉处理概述
前面介绍了信号的基本信息和信号的发送,这里总结一下Linux中进程对信号的捕捉和处理,进程收到信号一般会设置一个信号处理函数来专门执行接收到信号后的操作,类似于中断一样。
在信号处理函数中,可以根据信号的不同来执行相应的操作,也可以读取信号所携带的信息。
Linux系统中对信号的处理主要由signal()
函数和sigaction()
函数来处理,有时还会用到pause()
函数,下面对这些函数一一介绍。(SIGKILL和SIGSTOP信号不可以被捕捉或忽略)
signal()函数
signal()函数用来设置进程接收到信号的动作,在shell下输入man signal
可以获取其函数原型:
#include <signal.h>
typedef void ( *sighandler_t ) ( int );
sighandler_t signal( int signum, sighandler_t handler );
- signum是指定信号的编号
- handler是对应信号处理函数的指针,它所指向的函数类型是sighandler_t,且所指向的函数有一个int型参数,返回值为void
- signal()函数执行成功时返回信号处理函数的指针,有错误时返回SIG_ERR(即-1)
下面通过一段代码来实现signal()
对信号的捕捉和处理:
#include <stdio.h>
#include <signal.h>
/* 信号处理函数 */
void handler_sigint( int signo )
{
printf("recv SIGINT\n");
}
int main( void )
{
/* 安装信号处理函数 */
signal( SIGINT, handler_sigint );
while( 1 )
;
return 0;
}
可以在shell中按下<Ctrl+C>来向进程发送SIGINT信号,进程收到信号后会立即执行信号处理函数,即在屏幕上打印出:recv SIGINT
要结束进程的时候按下<Ctrl+>即可(发送了SIGSTOP信号),也可以使用kill命令结束进程
程序说明:
程序首先使用signal()
函数安装了SIGINT的信号处理函数,然后进入死循环,当接收到SIGIINT信号时,立即跳转执行信号处理函数,从而打印出信息,然后返回主函数继续死循环。
sigaction()函数
sigaction()函数也可以对信号进行捕捉和调用信号处理函数,在shell下输入man sigaction
可以获取其函数原型:
#include <signal.h>
int sigaction( int signum, const struct sigaction *act, struct sigaction *oldact );
- signum就是指定的信号的编号
- act指向新的信号处理函数
- oldact会存储旧的信号处理函数
- struct sigaction结构体的定义如下:
struct sigaction
{
void ( *sa_handler )( int );
void ( *sa_sigaction )( int, siginfo_t, void* );
sigset_t sa_mask;
int sa_flags;
void ( *sa_restorer )( void );
}
对结构体的成员进行说明:
- 前俩个成员被定义为共用体,即同一时刻俩个参数只有一个有效。
- sa_handler可以是常数SIG_DFL或SIG_IGN,也可以是一个函数名,指向信号处理函数
- sa_sigaction也是用来指向信号处理函数的,但其有三个参数,第一个参数是信号编号、第二个参数是指向siginfo_t的指针,此参数可以用来传递数据、第三个参数一般不用
- sa_mask声明了一个信号集
- 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++;
printf("the value of temp is :%d\n", temp);
printf("in handler_sigint, after sleep\n");
}
int main( void )
{
struct sigaction act;
/* 配置act结构体 */
act.sa_handler = handler_sigint;
/* 表示支持信号的嵌套处理 */
act.sa_flags = SA_NOMASK;
/* 安装信号处理函数,act中就包含了信号处理函数的信息 */
sigaction( SIGINT, &act, NULL );
while( 1 )
;
return 0;
}
程序的执行结果如下:
当把act.sa_flags = SA_NOMASK;
注释去掉后的执行结果如下:
去掉后,sigaction按照默认方式阻塞正在排队的信号,因为SIGINT是不可靠信号,不可靠信号不支持排队,造成了信号丢失
pause()函数
pause()函数使调用进程挂起,直至捕捉到一个信号,在shell下输入man pause
可获取函数原型:
#include <unistd.h>
int pause( void )
pause()函数会令目前进程暂时进入睡眠状态,直到被信号所中断,该函数只返回-1。