乐趣区

关于linux:Linux系统编程信号捕捉

后面咱们学习了信号产生的几种形式,而对于信号的解决有如下几种形式:

  1. 默认解决形式;
  2. 疏忽;
  3. 捕获。

信号的捕获,说白了就是抓到一个信号后,执行咱们指定的函数,或者执行咱们指定的动作。上面具体介绍两个信号捕获操作参数:signalsigaction

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 开发学习路线图

也心愿有小伙伴能退出我,把这份电子书做得更完满!

有播种?心愿老铁们来个三连击,给更多的人看到这篇文章

举荐浏览:

  • 干货 | 程序员进阶架构师必备资源免费送
  • 神器 | 反对搜寻的资源网站
退出移动版