博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
问题:Linux 信号处理,当连续给一个进程同时发送多个信号时,部分信号丢失而未得到处理
阅读量:4110 次
发布时间:2019-05-25

本文共 4678 字,大约阅读时间需要 15 分钟。

解释信号丢失问题:

阻塞,sigaction 函数有阻塞的功能,比如 SIGINT 信号来了,进入信号处理函数,默认情况下,在信号处理函数未完成之前,如果又来了一个 SIGINT 信号,其将被阻塞,只有信号处理函数处理完毕,才会对后来的 SIGINT 再进行处理,同时后续无论来多少个 SIGINT,仅处理一个 SIGINT,sigaction 会对后续 SIGINT 进行排队合并处理。
原文:

  1. 连续给一个进程发送多个相同信号时,部分信号丢失而未得到处理(使用 signal 函数处理信号),代码如下:
/* test2.c */#include 
#include
#include
// 信号处理函数使用的全局变量int count_sig = 0;void handleSig(int);void main(){
printf("main running...\n"); signal(SIGINT, handleSig); // 循环等待信号的到来 while(1){
sleep(1); printf("alive.\n"); } printf("done.\n");}// 信号处理函数void handleSig(int sig){
sleep(1); count_sig ++; printf("got signal. c:%d\n", count_sig);}

运行程序,执行结果如下(使用键盘向进程连续 发送 3 个终端中断信号,却 只有 2 个信号被处理函数处理 了):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test2 test2.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test2main running...^C^C^Cgot signal. c:1 	// 连续发送 3 个终端中断信号,却只有 2 个信号被处理got signal. c:2alive.alive.alive.alive.alive.Killed 		// 终止该进程:‘ kill -sigkill 39237 ’

再次运行该程序,结果如下(这次 连续发送更多的信号,并查看输出情况,发现***仅仅 2 个信号被处理***):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test2main running...^C^C^C^C^C^C^C^C^C^C^Cgot signal. c:1 // 连续发送更多的信号时,仅仅 2 个信号被处理got signal. c:2alive.alive.alive.Killed  	// kill 该进程

这是什么原因呢?

可能和 Linux 信号处理机制有关


  1. 实验:在一个信号处理(使用 signal 函数)过程期间,给进程发送另一个不同类型的信号:
/* test4.c */#include 
#include
#include
#include
int count_sig = 0;void handleSig(int);void main(){
printf("main running...\n"); signal(SIGINT, handleSig); // 处理 SIGINT 终端中断信号 signal(SIGALRM, handleSig); // 处理 SIGALRM 闹钟信号 // 循环等待信号 while(1){
sleep(1); printf("alive.\n"); } printf("done.\n");}// 信号处理函数void handleSig(int sig){
if(sig == SIGINT){
// 处理 SIGINT 终端中断信号 count_sig ++; printf("got signal: sigint. c:%d\n", count_sig); errno = 0; sleep(20); printf("got signal: sigint. done, sleep errno code:%d\n", errno); }else if(sig == SIGALRM){
// 处理 SIGALRM 闹钟信号 printf("got signal: sigalrm. done\n"); }}

执行结果如下(在第一个 信号 SIGINT 处理期间,(发送 SIGALRM 信号,使得当前的信号处理函数被中断)进程转而执行 SIGALRM 信号处理函数,在处理完第二个信号(SIGALRM)后,进程又返回到第一个信号处理函数中断时的位置,但是并没有重入 sleep 函数,而是从 sleep 中立即返回(sleep 函数调用的错误为 4),紧接着继续执行下面的 printf 语句):

  • 其中 sleep 函数的 errno code 错误码为 4 :Interrupted system call(被中断的系统调用),在睡眠期间,被第二个信号(SIGALRM)打断。
  • 从运行结果可以看出,两个信号处理函数交织在一起执行:SIGINT 的处理函数还未运行结束时就收到 SIGALRM 信号,导致函数执行被中断
  • 实验 3 中,将使用 sigaction 函数调用避免同时接收多个信号时,对处理函数的 竞态 问题。
ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test4 test4.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test4main running...^Cgot signal: sigint. c:1		// 发送了 1 个 SIGINT 终端中断信号got signal: sigalrm. done		// 发送 1 个 SIGALRM 信号,成功处理got signal: sigint. done, sleep errno code:4		// 紧接着第一个 SIGINT 信号的处理函数执行完毕alive.alive.got signal: sigalrm. done   // 单独发送一个 SIGALRM 信号,成功处理alive.alive.^Cgot signal: sigint. c:2   // 发送第二个 SIGINT 信号,下面的两行输出与前面的情况一致got signal: sigalrm. donegot signal: sigint. done, sleep errno code:4alive.alive.alive.alive.Killed 		// kill 该进程

  1. 使用 sigaction 函数解决信号处理函数的竞态问题),改写实验 2 中的 signal 函数部分,观察区别,代码如下:
/* test5.c */#include 
#include
#include
#include
int count_sig = 0;void handleSig(int);void main(){
printf("main running...\n"); struct sigaction act; act.sa_handler = handleSig; sigemptyset(&act.sa_mask); // 将信号 SIGALRM 加入到进程屏蔽字中, // 在 SIGINT 信号处理期间,接收到的 SIGALRM 信号会排队直到 SIGINT 信号处理完毕, // !信号屏蔽 不是遗弃信号,被屏蔽的信号会被排队,并在随后得到处理! sigaddset(&act.sa_mask, SIGALRM); act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, 0); sigaction(SIGALRM, &act, 0); while(1){
sleep(1); printf("alive.\n"); } printf("done.\n");}void handleSig(int sig){
if(sig == SIGINT){
count_sig ++; printf("got signal: sigint. c:%d\n", count_sig); errno = 0; int res = sleep(20); printf("got signal: sigint. done, sleep errno code:%d\n", errno); }else if(sig == SIGALRM){
printf("got signal: sigalrm. done\n"); }}

执行结果如下(信号被排队,依次处理):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test5 test5.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test5main running...alive.alive.^Cgot signal: sigint. c:1got signal: sigint. done, sleep errno code:0 	// sleep 调用未被中断got signal: sigalrm. done		// SIGINT 信号处理完毕后,SIGALRM 信号得到处理alive.alive.got signal: sigalrm. done		// 单独发送 SIGALRM 信号alive.alive.^Cgot signal: sigint. c:2		// 再次尝试got signal: sigint. done, sleep errno code:0got signal: sigalrm. donealive.alive.Killed 		// kill 该进程

转载地址:http://vclsi.baihongyu.com/

你可能感兴趣的文章
去哪儿一面+平安科技二面+hr面+贝贝一面+二面产品面经
查看>>
element ui 弹窗在IE11中关闭时闪现问题修复
查看>>
vue 遍历对象并动态绑定在下拉列表中
查看>>
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
python __future__
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>
pytorch(二)
查看>>
pytorch(三)
查看>>
pytorch(四)
查看>>
pytorch(5)
查看>>
pytorch(6)
查看>>
opencv 指定版本下载
查看>>
ubuntu相关
查看>>
C++ 调用json
查看>>
nano中设置脚本开机自启动
查看>>
动态库调动态库
查看>>
Kubernetes集群搭建之CNI-Flanneld部署篇
查看>>
k8s web终端连接工具
查看>>