经常混淆的两个信号就是SIGCLD以及SIGCHLD,信号SIGCLD源于System V,该信号的含义与源自BSD的信号SIGCHLD不一致。同时POSIX.1信号也称为SIGCHLD.源自BSD的信号SIGCHLD的语义比较正常,当该信号出现的时候,表示子进程的状态发生了变化,然后我们需要调用一个wait函数来查看究竟发生了什么。

System V对于SIGCLD的处理历史以来都与其他信号不同,基于SVR4i的系统保持了这个有问题的传统,如果我们使用函数signal或者是sigset(SVR3中用于设置信号处理函数的函数)设置信号的处理函数,SIGCLD早期的处理包含如下行为:

  1. 如果将信号处理函数指定为SIG_IGN,调用进程的子进程将永远不会产生僵尸进程。注意这与该信号的默认处理时不同的,在图10.1中提到其默认处理时忽略。取而代之的是,当子进程终止的时候,子进程的状态将被抛弃,如果其父进程接着调用其中一个wait函数,调用进程将被阻塞直到所有子进程终止,然后wait函数返回-1,并且errno被设置为ECHILD.(注意:信号的默认处理时忽略信号,但是该默认处理方式并不会产生上述行为,而是我们必须将该信号的处理函数设置为SIG_IGN.)

    POSIX.1并没有指定当SIGCHLD被忽略的时候会发生什么,所以上述处理也是被允许的,而XSI选项要求这一处理被信号SIGCHLD支持。
    4.4BSD在SIGCHLD被忽略的时候总是生成僵尸进程,如果我们想要避免僵尸进程的产生,我们必须wait所有的子进程,在SVR4中,只要调用signal或者是sigset中的一个将SIGCHLD的处理函数设置为SIG_IGN,僵尸进程就永远不会产生,本书中描述的4个平台都与SVR4的相同。
    使用函数sigaction而言,我们可以设置SA_NOCLDWAIT标志来避免僵尸进程,该行为对于本书中介绍的4个平台都是支持的。

  2. 如果我们设置SIGCLD的处理函数,内核就会立即检查是否有子进程处于等待处理的情况,若有,则立即调用SIGCLD函数。

上述第二项改变了我们编写信号处理函数的方式,正如下面的例子中将会讲到的一样.

Example

在10.4节中提到,在信号处理函数中的第一件事就是再次调用signal函数,这样处理时为了最小化信号处理函数被还原为默认处理的时间窗口,图10.6就是按照这一规则进行编写的程序,但是该程序在传统的System V平台上并不能很好地工作,其输出将是连续不断的字符串”SIGCLD received”,最会进程由于堆栈空间溢出而异常终止。

  1. #include "apue.h"
  2. #include <sys/wait.h>
  3. static void sig_cld(int signo);
  4. int main()
  5. {
  6. pid_t pid;
  7. if(signal(SIGCLD, sig_cld) == SIG_ERR)
  8. perror("signal error");
  9. if((pid = fork()) < 0)
  10. {
  11. perror("fork error");
  12. }
  13. else if(pid == 0)
  14. {
  15. /* child process*/
  16. sleep(2);
  17. _exit(0);
  18. }
  19. pause(); /*parent process*/
  20. exit(0);
  21. }
  22. static void sig_cld(int signo)
  23. {
  24. pid_t pid;
  25. int status;
  26. printf("SIGCLD received\n");
  27. if(signal(SIGCLD, sig_cld) == SIG_ERR) /*reestablish handler*/
  28. perror("signal error");
  29. if((pid = wait(&status)) < 0) /*fetch child status*/
  30. perror("wait error");
  31. printf("pid = %d\n", pid);
  32. }

上述程序的问题是:在信号处理函数的开始位置调用了函数signal,这对应于上面讨论的第二项–内核检查是否有子进程需要wait for(在上述程序中符合这一情况,因为我们正在处理SIGCLD信号),所以对于signal函数的调用会产生另一次对于信号处理函数的调用,信号处理函数反过来又会调用signal函数,于是整个进程就会不断地重复运行。
为了解决上述程序的问题,我们必须将对函数signal的调用移动到wait函数之后,通过这样做我们在捕获到子进程的终止状态以后再调用signal函数,该信号仅仅在其他子进程终止的时候才会再次产生。

POSIX.1声明:在我们建立SIGCHLD的信号处理函数的时候,如果已经存在一个还没有被wait的终止的子进程,信号是否需要生成并没有指定,因此上述情况是允许的,但是对于POSIX.1而言,在信号产生以后并不会复位信号处理函数为默认函数(假设我们正在使用的是POSIX.1的sigaction函数来设置信号处理函数),便没有需要在信号处理函数中再次调用函数signal了。于是上述问题就消失了。

来自为知笔记(Wiz)

转载于:https://www.cnblogs.com/U201013687/p/5518345.html

10.7 SIGCHLD定义相关推荐

  1. Go 学习笔记(10)— 数组定义、数组声明、数组初始化、访问数组、数组相等、向函数传递数组

    1. 数组定义 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 2. 声明数组 Go 语言数组声明需要指定元素类型及元素个数,语 ...

  2. 习题10.3 分别定义Teacher类和Cadre类,采用多重继承方式由这两个类派生出新类Teacher_Cadre类。

    分别定义Teacher(教师)类和Cadre(干部)类,采用多重继承方式由这两个类派生出新类Teacher_Cadre(教师兼干部)类.要求: ① 在两个基类中都包含姓名.年龄.性别等数据成员. ② ...

  3. react学习(10)----react数组定义 从0开始 直接加个0下标空

    {title: '状态',dataIndex: 'status',render: (text, row) => {let arr = ['', '未开始', '进行中', '已结束', '已作废 ...

  4. 定义一个时钟类(TimeDemo),属性有:时、分、秒(默认值10时30分),方法有展示当前时间、过1秒,过1分钟,过1小时后的时分秒;在测试类中实现过10秒,过10分,过10小时后的时间展示

    题目: 定义一个时钟类(TimeDemo),属性有:时.分.秒(默认值10时30分),方法有展示当前时间.过1秒,过1分钟,过1小时后的时分秒:定义成员方法分别对时.分.秒进行加减运算,保证运算后时间 ...

  5. ADPRL - 近似动态规划和强化学习 - Note 10 - 蒙特卡洛法和时序差分学习及其实例 (Monte Carlo and Temporal Difference)

    Note 10 蒙特卡洛法和时序差分学习 Monte Carlo and Temporal Difference 蒙特卡洛法和时序差分学习 Note 10 蒙特卡洛法和时序差分学习 Monte Car ...

  6. c语言宏定义_掌握C语言,中文编程不是梦

    文/Edward 前面我们在讲节程序编译的时候,编译器做的第一步就是预处理.C语言的预处理,其实是编译器在对整个工程编译之前做的一些文本性质的工作,例如我们经常使用的#include,这就是一个典型的 ...

  7. int * * a[10] int * (*a)[10]和 int(*a[10])() 是什么意思

    int* (*a)[10]; a是一个指向包含10个int型指针元素的数组. 比如: #include <stdio.h>int main() {// 定义数组,包含10个int*int* ...

  8. Oracle编程入门经典 第10章 PLSQL

    目录 10.1          总览... 1 10.2          基于程序块的开发... 1 试验:PL/SQL程序块... 2 工作原理... 2 块嵌套... 2 10.3       ...

  9. 【机器学习入门笔记7:TensorFlow常量变量的定义】20190210

    2019-02-10  by 崔斐然 学习过程: #基础语法  #API调用   #原理 #高级语言一般都有基础数据类型 运算符  流程  字典 数组 元组 import tensorflow as ...

最新文章

  1. docker 命令详细解释
  2. 丁克是什么意思,丁克家庭是什么意思,丁克家庭为什么越来越多
  3. odbc mysql导出access_将mysql数据导入access数据库
  4. spring使用 hibernate jpa JpaRepository
  5. 【java】打印一个对象即打印出该对象toString()返回值
  6. lte基站可以做ntp server吗?_你手机信号强吗?学会这几招快速提升你的手机信号...
  7. wind金融数据接口python_Wind量化接口
  8. linux su 拒绝权限,Linux禁止非WHEEL用户使用su命令
  9. 彻底弄明白Gradle相关配置
  10. Vultr与阿里云结合自动换IP的解决方案
  11. python模拟登录163邮箱_python模拟登陆163邮箱并获取通讯录 | 学步园
  12. Unity3D学习 ③ 摄像机视角跟随
  13. 字符串和转义字符的知识和应用
  14. 【Android开发日记】jsonObject = new JSONObject(info)报错 A JSONObject text must begin with '{' at character
  15. 用Photoshop制作LOMO风格暗角效果照片
  16. jquery mouse事件小坑
  17. 给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。
  18. 如何自定义百度云常用服务器,经验分享:如何将百度云做成网站文件服务器
  19. [生存志] 第53节 晏子春秋录纯臣
  20. java个性签名_程序员用搞笑个性签名

热门文章

  1. 锐捷深入油田场景 助力胜利油田生产物联网通向“新胜利”之路
  2. android类京东到家开发源码
  3. matlab中surf怎么改变颜色_MATLAB作图
  4. c++ - 第1节 - c++入门
  5. 《流浪地球2》数字生命与我们的距离
  6. 准!武汉大学和高德组队 拿下国际顶赛“车载环境下的手机定位”组别冠军
  7. Ribbon负载均衡策略、懒加载及饥饿加载
  8. win10必须禁用的服务_Windows Event Log服务能否关闭?Win10系统Event Log服务详解
  9. 手机备忘录怎么将图片转文字
  10. java实现基于AmazonS3文件上传、下载、删除操作