本文共 4678 字,大约阅读时间需要 15 分钟。
解释信号丢失问题:
阻塞,sigaction 函数有阻塞的功能,比如 SIGINT 信号来了,进入信号处理函数,默认情况下,在信号处理函数未完成之前,如果又来了一个 SIGINT 信号,其将被阻塞,只有信号处理函数处理完毕,才会对后来的 SIGINT 再进行处理,同时后续无论来多少个 SIGINT,仅处理一个 SIGINT,sigaction 会对后续 SIGINT 进行排队合并处理。 原文:
/* 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 信号处理机制有关/* 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 语句):
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 该进程
/* 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/