共计 2325 个字符,预计需要花费 6 分钟才能阅读完成。
后面咱们学习了信号产生的几种形式,而对于信号的解决有如下几种形式:
- 默认解决形式;
- 疏忽;
- 捕获。
信号的捕获,说白了就是抓到一个信号后,执行咱们指定的函数,或者执行咱们指定的动作。上面具体介绍两个信号捕获操作参数:signal和sigaction。
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 这两个成员一个曾经被弃用了,另一个很少应用,所以咱们暂且不论它们,重点把握剩下的三个。
① sa_handler:指定信号捕获后的处理函数,即注册回调函数。该成员也能够赋值为 SIG_IGN,示意疏忽该信号,也可注册为 SIG_DFL,示意执行信号的默认动作。
② sa_mask:长期阻塞信号集(或信号屏蔽字)先来看这样一个情景:
某个信号曾经注册了回调函数,当内核传递这个信号过去时,会先通过一个阻塞信号集,先阻塞掉局部信号。再去执行对应的回调函数。如下图示:
如果说,这个回调函数回调执行的工夫比拟长,比方 2 秒,在这 2 秒里,又有其它的信号过去,那过程是暂停以后回调函数,去响应新的信号,还是不论新来的信号,先把以后回调函数解决完再说?
正确的做法是,在执行回调函数期间,应用 sa_mask 长期的去代替过程的阻塞信号集,保障回调函数安心的执行结束,再解除代替。留神:这个过程仅仅产生在回调函数执行期间,是临时性的设置。
③ 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,公众内回复 1024 可收费取得 5T 技术材料,包含:Linux,C/C++,Python,树莓派,嵌入式,Java,人工智能 ,等等。公众号内回复 进群,邀请您进高手如云技术交换群。
最初,最近很多小伙伴找我要Linux 学习路线图,于是我依据本人的教训,利用业余时间熬夜肝了一个月,整顿了一份电子书。无论你是面试还是自我晋升,置信都会对你有帮忙!
收费送给大家,只求大家金指给我点个赞!
电子书 | Linux 开发学习路线图
也心愿有小伙伴能退出我,把这份电子书做得更完满!
有播种?心愿老铁们来个三连击,给更多的人看到这篇文章
举荐浏览:
- 干货 | 程序员进阶架构师必备资源免费送
- 神器 | 反对搜寻的资源网站