博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SIGCHLD信号
阅读量:4987 次
发布时间:2019-06-12

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

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。

转载于:https://www.cnblogs.com/love-DanDan/p/8724236.html

你可能感兴趣的文章
html5 iphone苹果手机主屏幕 触摸滑动效果
查看>>
Android动画学习笔记
查看>>
Delphi 完整的Bug决议工具EurekaLog的使用
查看>>
libusb 开发者指南-牛胜超(转)
查看>>
C - 继续畅通工程 最小生成树
查看>>
Java基础知识强化之集合框架笔记01:集合的由来与数组的区别
查看>>
Java基础知识强化之IO流笔记71:NIO之 NIO的(New IO流)介绍
查看>>
laravel artisan 工具心得
查看>>
软工作业 4:结对项目之词频统计——基本功能
查看>>
linux vim vi编辑时撤销输入操作
查看>>
java utils
查看>>
maven打包
查看>>
CSS
查看>>
初学springboot, 如何快速使用maven搭建springboot项目呢
查看>>
POJ 3380 最大流
查看>>
iOS学习之 plist文件的读写
查看>>
写的一些推广方法 拿出来分享下
查看>>
【公告】CSDN个人空间将于2014年4月20日全新改版上线
查看>>
C#:MVC打印PDF文件
查看>>
在学习mybatis中的接口是发生错误Type interface com.souvi.ibatis.xxxMapper is not known to the MapperRegistry...
查看>>