35-标准信号及其不可靠性
来源:互联网 发布:sis第一网络会所地址 编辑:程序博客网 时间:2024/05/20 13:08
信号你会发了,也会捕了,但是还有好些个坑没填上。之前一直强调发送信号 1 - 31 号,实际上,还有 32-64 号信号。为什么不发 32-64 号信号,是因为32-64号和前面的 1- 31 号不属于一个范畴。
1-31号,被规定为 standard signals,也就是标准信号。32-64号信号,被规定为 real-time signals,也就是实时信号。目前我们只关心标准信号,而不关心实时信号。
需要特别强调的是,标准信号是不可靠的,不可靠的意思是如果同时来了很多相同的信号,而且还没来得及处理,这些相同的信号就会被合并成一个信号。实时信号就没有这个问题,只要来一次,就会处理一次。
下面以实例来讲解标准信号到底是有多么的不可靠。另外,这个实例会使用异步的方式来 wait 状态发生改变的子进程(比如退出,停止,发生段错误等等),我们再也不用在主函数里去 wait 子进程回收僵尸进程了。
1. 不可靠是什么样子
为了能够很快说明问题,请复制后面的代码编译运行。
这段代码的功能:main 函数生成 10 个子进程,每个子进程一生出就直接退出,只有一个子进程访问非法内存不正常退出。最后 main 函数每隔 10 秒在屏幕打点。
除此之外,这段程序注册了 SIGCHLD 信号处理函数。当有子进程状态发生改变时,会执行信号处理函数。信号处理函数主要就是 wait 子进程,并打印子进程的退出码或者打印子进程被何种信号终止或停止。最后信号处理函数会 sleep 1 秒钟。
- 代码
// stdsig.c#include <unistd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/wait.h>#include <sys/types.h>void waitchild(int sig) { int status; pid_t pid; if ((pid = waitpid(-1, &status, WUNTRACED | WCONTINUED)) > 0) { if (WIFEXITED(status)) { printf("child %d exited! return code = %d\n\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("child %d terminated by signal %d\n\n", pid, WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("child %d stopped by signal %d\n\n", pid, WSTOPSIG(status)); } else if (WIFCONTINUED(status)) { printf("child %d continued\n\n", pid); } } sleep(1);}void child(int n) { if (n == 9) *((int*)0) = 0; exit(n + 1); }int main() { printf("I'm %d\n", getpid()); if (SIG_ERR == signal(SIGCHLD, waitchild)) { perror("signal SIGSTOP"); } int n = 10; pid_t pid; while(n--) { pid = fork(); if (pid == 0) { child(n); } else if (pid == -1) { perror("fork"); } } while(1) { write(STDOUT_FILENO, ".", 1); sleep(10); } return 0;}
- 编译
$ gcc stdsig.c -o stdsig
- 运行
$ ./stdsig
1.1 结果分析
在我机器上运行的结果如下:
I'm 7699.child 7706 exited! return code = 4child 7700 exited! return code = 10..............
你会很惊讶的发现,你只处理了 2 个子进程发来的信号,还有 8 个信号去哪了?另外,再打开一个终端,执行 ps a
,你会发现有一堆僵尸在那等着吃掉你的脑子。
实际上,在信号处理函数 waitchild 中还没来得及结束(因为 sleep,对于CPU来说,1 秒简直比人类的 1 个世纪还要长),新的 SIGCHLD 信号又来了,而操作系统对此的操作是将其和前一个 SIGCHLD 信号合并。
1.2 改进方案
弄清楚原因后,我们就知道在 waitpid 函数正在执行时,可能已经有多个子进程结束了。因此只需修改一处——将waitchild 的 if 判断改为 while 循环。即下面这样:
……- if ((pid = waitpid(-1, &status, WUNTRACED | WCONTINUED)) > 0) { // 将这一行改成下面那一行+ while ((pid = waitpid(-1, &status, WUNTRACED | WCONTINUED)) > 0) {……
重新编译运行,发现所有子进程正常回收。
2. 总结
- 知道信号有可靠的和不可靠的
- 理解标准信号的不可靠性指的是什么
- 掌握异步回收子进程
- 35-标准信号及其不可靠性
- UDP协议的不可靠性
- UDP协议之不可靠性
- 标准信号(signal.h)
- 一些标准信号
- linux信号及其含义
- SIGHLD信号及其应用
- 信号理论: 信号集及其映射
- NGOSS标准及其进展
- 数字电视及其标准
- 关于POSIX标准中的信号
- Android系统客制化信号标准
- 信号完整性问题及其解决方法
- linux 各种信号及其含义
- 信号两及其相关函数
- linux 各种信号及其含义
- Linux信号捕捉及其处理
- 信号互相关及其应用
- Linux常用命令大全
- android OnGestureListener滑动事件详解
- 文件查询-私房菜学习笔记
- 联发科MTK手机线刷错误代码信息解译以及解决方法大全
- [Mapbox GL]创建时间滑动条
- 35-标准信号及其不可靠性
- win10 关于oracle和PLSQL Developer的安装、配置,以及常见问题解决
- 图形化调试 - unity使用GL库画线
- html5 canvas实现高并发视频弹幕功能
- Java中Console类源码
- Lua学习笔记
- BAD PASSWORD: it is too simplistic/systematic
- JQuery之禁用radio、select、checkbox
- ORA-12514 TNS:listener does not currently know of service requested in connect descriptor