SIGCHLD信号回收子进程

SIGCHLD信号回收子进程

代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>


void handler(int signo)
{
    int status;    
    pid_t pid;
    while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status))
            printf("child %d exit %d\n", pid, WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
    }


}



int main()
{
    pid_t pid;
    int i = 0;

    //循环创建子进程
    for(i = 0; i < 10; i++)
    {
        pid = fork();
        if (pid == 0)
        {
            break;
        }
        else if (pid < 0)
        {
            perror("pid error:");
            exit(1);
        }
    
    }
    if (pid > 0)
    {
        sigset_t set,oldmask;
        sigemptyset(&set);
        sigemptyset(&oldmask);
        sigaddset(&set,SIGCHLD);
        //屏蔽
        sigprocmask(SIG_BLOCK,&set,NULL);
        struct sigaction act;
        //安装信号
        act.sa_flags = 0;
        act.sa_handler = handler;
        sigemptyset(&act.sa_mask);
        //父进程
        sigaction(SIGCHLD,&act,NULL);

        //开启
        sigprocmask(SIG_SETMASK,&oldmask,NULL);
        while (1);


    }
    else if (pid == 0)
    {
        int n = 1;
        while (n--) {
            printf("child ID %d\n", getpid());
            sleep(1);
        }
        return i + 1;

    }



    return 0;
}

在这里插入图片描述

问题

如果我们把while循环改成if,相当于每个子进程运行完后就会发送SIGCHLD信号,父进程通过捕获,用waitpid来回收子进程,可以吗?

void handler(int signo)
{
    int status;    
    pid_t pid;
    if ((pid = waitpid(0, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status))
            printf("child %d exit %d\n", pid, WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
    }


}

在这里插入图片描述
但是,运行的效果却并不如我们所想象的。这是为什么呢?
当父进程收到第一个信号的时候,将会执行handler这个函数,在执行函数期间,子进程仍会发出信号,在Linux中1-31号信号是非实时信号,不支持排队,信号丢失了,造成了这个原因。

注意点

代码如下(示例):

        sigset_t set,oldmask;
        sigemptyset(&set);
        sigemptyset(&oldmask);
        sigaddset(&set,SIGCHLD);
        //屏蔽
        sigprocmask(SIG_BLOCK,&set,NULL);
        struct sigaction act;
        //安装信号
        act.sa_flags = 0;
        act.sa_handler = handler;
        sigemptyset(&act.sa_mask);
        //父进程
        sigaction(SIGCHLD,&act,NULL);

        //开启
        sigprocmask(SIG_SETMASK,&oldmask,NULL);

为什么要采用屏蔽和开启信号的方式呢?
原因在于在程序运行中,为了避免父进程还没注册完信号,子进程就发送信号的情况。信号阻塞时发送,信号的递送会等到信号解除后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenshida_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值