利用信号捕捉函数回收子进程

SIGCHLD信号

  只要子进程发生变化就会产生SIGCHLD信号通知父进程:
   1.子进程终止时;
   2.子进程接收到SIGSTOP信号停止时;
   3.子进程处在停止态,接收到了SIGCONT唤醒时。

利用信号捕捉函数回收子进程

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

void func(int arg)
{
    pid_t wpid;
    int status;
    while((wpid = waitpid(-1, &status, 0)) != -1) //一次响应回收多次
    {
        printf("waitpid:%d
", wpid);
        if (WIFEXITED(status))
        {
            printf("catch child id = %d  ret_val:%d
", wpid, WEXITSTATUS(status));
        }
    }
}

int main(int argc, char const *argv[])
{
    pid_t pid;
    sigset_t set;
    int ret;

    //设置SIGCHLD信号阻塞
    ret = sigemptyset(&set);

    if (-1 == ret)
    {
        perror("sigemptyset error");
        return -2;
    }    

    ret = sigaddset(&set, SIGCHLD);
    if (-1 == ret)
    {
        perror("sigaddset error");
        return -1;
    }
    
    ret = sigprocmask(SIG_BLOCK, &set, NULL);
    if (-1 == ret)
    {
        perror("sigprocmask error");
        return -1;
    }

    int i;
    for (i = 0; i < 5; i++)
        if ((pid = fork()) == 0)
            break;
    
    if (5 == i)
    {
        struct sigaction act;
        act.sa_handler = func;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGCHLD, &act, NULL);
        // 解除阻塞
        ret = sigprocmask(SIG_UNBLOCK, &set, NULL); 
        if (-1 == ret)
        {
            perror("sigprocmask error");
            return -1;
        }   
        printf("I am parent, pid = %d
", getpid());
        while(1);
    }
    else
    {
        printf("I am child , pid = %d
", getpid());
        return i;
    }
    
    return 0;
}

输出结果:

  注意:
   1.SIGCHLD信号默认是忽略的;
   2.当多个子进程同时死亡时产生多个SIGCHLD信号,但是只会处理一个,因为常规信号不排队,所以在信号响应函数中应该循环判断是否有子进程死亡;
   3.需要注意程序一开始应该阻塞SIGCHLD信号,防止子进程运行过快,还没有设置信号响应函数就已进运行完了。
   4.父进程不应先与子进程死亡。

原文地址:https://www.cnblogs.com/ding-ding-light/p/14279460.html