[2022.6.5][10 信号]使用signal函数捕获信号并处理

1 signal介绍

先看下函数声明:

#include 
//若成功,返回该Unix系统信号之前的信号处理函数地址;若失败,返回SIG_ERR
void (*signal(int signo, void (*func)(int)))(int);

signo参数是Unix系统信号。
func的值是常量SIG_IGN,常量SIG_DFL或当收到此信号后要调用的函数地址。若指定SIG_IGN,则向内核表示忽略此信号(注意,SIGKILL和SIGSTOP不能忽略);若指定SIG_DFL,则表示接收到此信号的动作是系统默认动作;若指定信号处理函数时,我们称这种处理为捕捉该信号。
使用如下的typedef可简化声明:

typedef void Sigfunc(int);
Sigfunc *signal(int , Sigfunc *);

注意:signal函数的形参表示的函数指针指的是对该Unix系统信号设置的信号处理函数;
signal函数的返回值表示的函数指针表示该Unix系统信号之前的信号处理函数。
而函数指针的返回值为空,形参为一个int值。
如果查看头文件,可以找到如下声明:

#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1

这些常量表示"指向函数的指针,该函数要求一个整型参数,而且无返回值"。

2 使用signal函数捕获信号并处理

如下程序捕捉两个用户定义的信号。

#include 
#include 
#include static void sig_usr(int);    /* one handler for both signals */int main(void)
{void (*func1)(int);void (*func2)(int);if ( (func1 = signal(SIGUSR1, sig_usr)) == SIG_ERR) {printf("can't catch SIGUSR1 \n");} else {printf("catch SIGUSR1 func1:%p \n", func1);// signal返回值表示对信号SIGUSR2之前的信号处理函数,SIG_DFLif (func1 == SIG_DFL) {printf("func1 == SIG_DFL \n");}}if ( (func2 = signal(SIGUSR2, sig_usr)) == SIG_ERR) {printf("can't catch SIGUSR2 \n");} else {printf("catch SIGUSR2 1 func2:%p \n", func2);// signal返回值表示对信号SIGUSR2之前的信号处理函数,SIG_DFLif (func2 == SIG_DFL) {printf("func2 == SIG_DFL \n");}}if ( (func2 = signal(SIGUSR2, sig_usr)) == SIG_ERR) {printf("can't catch SIGUSR2 \n");} else {printf("catch SIGUSR2 2 func2:%p \n", func2);// signal返回值表示对信号SIGUSR2之前的信号处理函数,sig_usrif (func2 != NULL) {func2(77);}}for ( ; ; ) {pause();printf("after pause <<<<<<< \n");}
}static void sig_usr(int signo)        /* argument is signal number */
{if (signo == SIGUSR1)printf("received SIGUSR1\n");else if (signo == SIGUSR2)printf("received SIGUSR2\n");elseprintf("received signal %d\n", signo);
}

pause函数会使调用函数在接收到一个信号前挂起。
我们使该程序在后台运行,并用kill命令将信号发送给它。

$ ./sigusr &
[2] 4015
catch SIGUSR1 func1:(nil)
func1 == SIG_DFL
catch SIGUSR2 1 func2:(nil)
func2 == SIG_DFL
catch SIGUSR2 2 func2:0x4006f7
received signal 77
$ kill -USR1 4015
received SIGUSR1
after pause <<<<<<<
$ kill -USR2 4015
received SIGUSR2
after pause <<<<<<<
$ kill 4015

该程序不捕捉SIGTERM信号,对该信号的系统默认动作是终止。

3 注意

1 启动程序
exec函数将原来设置为要捕获的信号都更改为默认动作,因为信号捕获函数的地址在所执行的新的程序文件中已无意义。
2 创建进程
当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为子进程开始复制了父进程的内存映像,所以信号捕获函数的地址在子进程中是有意义的。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部