这篇文章主要介绍了Linux如何实现信号捕捉,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
##signal函数
函数原型:
sighandler_t signal(int signum, sighandler_t handler);
其中,sighandler定义是这样的:typedef void (*sighandler_t)(int);
函数作用:注册一个信号捕捉函数,也就是说,收到了某个信号,就执行它所注册的回调函数。
函数参数:
signum:信号编号,尽量用宏来写,而别用数字,这样更适合跨平台;
handler:注册的回调函数;
函数缺陷:
由于历史原因,该函数在不同版本的Unix和Linux系统中可能起到的效果不一样,所以跨平台性不佳,尽量避免使用它,取而代之使用通用性更好的sigaction函数。
#include <stdio.h> #include <signal.h> void func() { printf("SIGQUIT catched!\n"); } int main() { signal(SIGQUIT, func); while(1); }
##sigaction函数
函数原型:
int sigaction(int signum, const struct sigaction act, struct sigaction oldact);
函数作用:与signal函数类似,用来注册一个信号捕捉函数;
返回值:
成功:0;失败:-1,并设置errno;
参数:
signum:信号编号,尽量用宏来写,而别用数字,这样更适合跨平台;
act:传入参数,新的信号捕捉方式;
oldact:传出参数,旧的信号捕捉方式
这里特别要注意参数中struct sigaction结构体,这也是这个函数的难点所在,下面详细说明:
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_restorer和sa_sigaction这两个成员一个已经被弃用了,另一个很少使用,所以我们暂且不管它们,重点掌握剩下的三个。
(1) sa_handler:指定信号捕捉后的处理函数,即注册回调函数。该成员也可以赋值为SIG_IGN,表示忽略该信号,也可注册为SIG_DFL,表示执行信号的默认动作。
(2) sa_mask:临时阻塞信号集(或信号屏蔽字)先来看这样一个情景:
某个信号已经注册了回调函数,当内核传递这个信号过来时,会先经过一个阻塞信号集,先阻塞掉部分信号。再去执行对应的回调函数。如下图示:
假如说,这个回调函数回调执行的时间比较长,比如2秒,在这2秒里,又有其它的信号过来,那进程是暂停当前回调函数,去响应新的信号,还是不管新来的信号,先把当前回调函数处理完再说?
正确的做法是,在执行回调函数期间,使用sa_mask临时的去替代进程的阻塞信号集,保证回调函数安心的执行完毕,再解除替代。注意:这个过程仅仅发生在回调函数执行期间,是临时性的设置。
(3) sa_flags:通常设置为0,表示使用默认属性。
再来看另外一个场景:
比如进程对SIGQUIT注册了回调函数,当回调函数在执行期间,又来了SIGQUIT函数,这时,进程是响应还是不响应该信号?这就是sa_flags的一个作用,当其设置为0时,表示使用默认属性,也就是先不响应该信号,而是执行完回调函数再处理此信号。
另外,阻塞的常规信号不支持排队,也就是说,执行回调函数期间,再来千百个同个信号时,系统只记录一次。而后面的32个实时信号则支持排队。
#include <stdio.h> #include <signal.h> #include <unistd.h> void func(int signal) { printf("SIGQUIT catched!\n"); sleep(2); //用来模拟回调函数执行很长时间 printf("func finished!\n"); } int main() { struct sigaction act; act.sa_handler = func; sigemptyset(&act.sa_mask); //先清空临时阻塞信号集 sigaddset(&act.sa_mask, SIGINT); // 执行回调函数期间,屏蔽SIGINT act.sa_flags = 0; sigaction(SIGQUIT, &act, NULL); //注册回调函数 while(1); return 0; }
感谢你能够认真阅读完这篇文章,希望小编分享的“Linux如何实现信号捕捉”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。