SIGCHLD的产生条件

子进程终止时

子进程接收到SIGSTOP信号停止时

子进程处在停止态,接受到SIGCONT后唤醒时

也就是说:子进程的运行状态发生变化就会发送SIGCHILD信号;这里的意思时,子进程比较依恋父母,自己发生变化就要给父母说一下。

借助SIGCHLD信号回收子进程

子进程结束运行,其父进程会收到SIGCHLD信号。该信号的默认处理动作是忽略。可以捕捉该信号,在捕捉函数中完成子进程状态的回收。不多说,上代码:

#include
<stdlib.h>

#include
<stdio.h>

#include
<sys/types.h>

#include
<sys/wait.h>

#include
<unistd.h>

#include
<signal.h>

void sys_err(char *p)

{

    perror(p);

    exit(1);

}

void do_sig_child(int
signal)

{

    printf("++++++++++++++++我是子进程,我的ID = %d\n", getpid());

}

void do_sig_parent(int
signal)

{

    int status;

    while ((waitpid(0, &status, WNOHANG)>0))//如果清理成功

    {

        if (WIFEXITED(status))

        {

            printf("子进程正常退出,状态:%d\n", WEXITSTATUS(status));

        }

        else
if (WIFSIGNALED(status))

        {

            printf("———子进程异常退出,状态:%d\n", WTERMSIG(status));

        }

    }

}

int main(void)

{

    int i = 0;

    pid_t pid;

    //屏蔽信号SIGCHLD

    for (; i != 10; i++)

    {

        if (!(pid = fork()))

        {

            break;

        }

        else
if (pid<0)

        {

            sys_err("fork error ");

        }

    }

    if (i<10)

    {

        do_sig_child(0);

        sleep(1);//防止在父进程还未注册信号捕捉函数的时候子进程死亡。这样父进程就不能回收已死亡的子进程。

    }

    else

    {

        struct
sigaction act, oldact;

        //修改信号处理动作

        act.sa_handler = do_sig_parent;

        act.sa_flags = 0;

        sigemptyset(&act.sa_mask);

        sigaddset(&act.sa_mask, SIGCHLD);

        if ((sigaction(SIGCHLD, &act, &oldact))<0)

        {

            sys_err("sigaction error");

        }

        while (1)

        {

            printf("父进程的ID = %d\n", getpid());

            sleep(1);

        }

        //还原信号处理动作

        if ((sigaction(SIGCHLD, &oldact, &act))<0)

        {

            sys_err("sigaction error");

        }

    }

    return 0;

}

现在,一切正常,运行结果:

现在我们来提问:如果每创建一个子进程后不使用sleep可以吗?可不可以将程序中,捕捉函数内部的while替换为if?为什么?

第一个问题我在代码中的注释已经写的很明白了,这里就不再说了。我们来说说另一个问题:捕捉函数do_sig_parent内部的while替换为if?为什么?即将代码 while((waitpid(0,&status,WNOHANG)>0))换为if((waitpid(0,&status,WNOHANG)>0))可以嘛?子进程一死亡就发送SIGCHLD信号给父进程,父进程收到后就执行捕捉函数。怎么不行呢?不管他行不行,我们试试就知道,实践出真知;结果如下:这次还有一个子进程未回收,不行了,大野的,这个win10子系统太牛,同样的代码在别人的Linux系统上错误能够完美重现,在这里能够完美避开。我试了好几十次才找到这一个错误。但是没事,反正有了。

来分析一下为啥if就不能完美的回收所有子进程:if只执行一次回收(因为到了那儿说明父进程收到信号了,也就是说一定有子进程死掉了。)但是若是某一个时刻有多个子进程同时死了,那么依据信号不进行排队的原理,就只有其中一个信号被处理。其他的被忽略。但是while就不一样了,就算同时来多个信号,但是while时循环执行,虽然信号处理先后顺序不一样,但是每个信号都会被处理啊(非阻塞的waitpid函数)。所以啊,当有多个子进程时,回收的时候用循环,不要用if。

SIGCHLD信号的更多相关文章

  1. unp TCP 客户端服务器回射程序中对SIGCHLD信号的处理

    第五章中,有一个例子模拟客户端并发的终止TCP连接,服务器捕捉并处理SIGCHLD信号并调用waitpid函数防止僵死进程的出现.信号处理函数中核心的一句是: , &statloc, WNOH ...

  2. linux下的僵尸进程处理SIGCHLD信号

    什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该 ...

  3. [转] linux下的僵尸进程处理SIGCHLD信号

    什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些 信息至少包括进程ID,进程的终止状态,以及 ...

  4. 三十一、Linux 进程与信号——SIGCHLD 信号、kill和raise函数以及alarm函数

    31.1 SIGCHLD 信号 子进程状态发生变化(子进程结束)产生该信号,父进程需要使用 wait 调用来等待子进程结束并回收它. 避免僵尸进程 #include <stdio.h> # ...

  5. linux下的僵尸进程处理SIGCHLD信号【转】

    转自:http://www.cnblogs.com/wuchanming/p/4020463.html 什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打 ...

  6. 僵尸进程与SIGCHLD信号

    什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该 ...

  7. 2次使用fork避免产生僵尸进程和不去处理SIGCHLD信号

    1.如下代码所示 #include <unistd.h> #include <sys/types.h> #include <unistd.h> int main(i ...

  8. 僵进程与SIGCHLD信号

    参考: https://www.cnblogs.com/webor2006/p/4014586.html wait()和waitpid()的参数解析:https://blog.csdn.net/csd ...

  9. linux有关信号的FAQ

    1.为什么会出现系统调用被中断的情况? 进程在执行一个低速系统调用而阻塞期间捕捉到一个信号时,该系统调用就被中断不再继续执行.该系统调用返回出错,其errno被设置为EINTR.这样处理的理由是:因为 ...

随机推荐

  1. 事件之onTouch方法的执行过程 及和 onClick执行发生冲突的解决办法

    转载:http://blog.csdn.net/jiangwei0910410003/article/details/17504315#quote 博主推荐: 风萧兮兮易水寒,“天真”一去兮不复还.如 ...

  2. Jmeter(二十九)Jmeter-Question之“Ant集成报告模板优化”

    也是在和朋友探讨的时候,发现一个问题,Jmeter在与Ant集成的时候,通常选用的模板是jmeter自带的两个样式表 该自带的样式,节省了大家搭建框架的时间,不需要自己重新写样式,当然也相对简洁: 做 ...

  3. SCCM 2012 R2实战系列之八:OSD(上)--分发全新Windows7系统

    今天将跟大家一起分享SCCM 中最为重要的一个功能---操作系统分发(OSD),在此文章中会讨论到OSD的初始化配置.镜像的导入.任务序列的创建编辑.并解决大家经常遇到的分发windows7系统分区盘 ...

  4. golang "text/template" 模板语法简明教程

    转自:https://www.cnblogs.com/Pynix/p/4154630.html [模板标签] 模板标签用"{{"和"}}"括起来   [注释] ...

  5. Doris与Hadoop yarn混合部署遇到的坑

    Doris默认端口 Yarn 默认端口: 如图,端口冲突,在混合部署的情况下,会出现2个问题: 1. Yarn ResourceManager启动不起来 解决办法:修改yarn.resourceman ...

  6. 02 Linux常见命令

    GUI图形界面 图形界面对于我们的Linux系统来说就是一个单独的软件程序,可以安装也可以不用安装: 我们常见的Linux下的常用图形软件为Gnome.KDE.XFce: GLI命令界面 Linux常 ...

  7. Java - 22 Java 多态

    Java 多态 多态是同一个行为具有多个不同表现形式或形态的能力. 多态性是对象多种表现形式的体现. 比如我们说"宠物"这个对象,它就有很多不同的表达或实现,比如有小猫.小狗.蜥蜴 ...

  8. day17常用模块1记忆

    常用模块(详细见'egon'博客)1. 时间模块time与datetime 1. 时间戳:time.time()        应用: 用来计算时间间隔  time.sleep(5) 延迟5秒    ...

  9. Linux free -m 详解命令

    如下显示free是显示的当前内存的使用,-m的意思是M字节来显示内容.我们来一起看看. 1 2 3 4 5 6 $ free -m                total       used    ...

  10. spring揭密学习笔记(2)-spring ioc容器:IOC的基本概念

    1. IoC的理念就是,让别人为你服务!2. 其实IoC就这么简单!原来是需要什么东西自己去拿,现在是需要什么东西就让别人送过来.一个生动的示例 3.三种依赖注入的方式 IoC模式最权威的总结和解释, ...