子进程死亡会给父进程发送 SIGCHLD 信号!(默认动作:父进程忽略该信号)此时父进程就可以捕捉该信号,利用回调函数使用 waitpid 回收子进程。
#include <stdio.h>#include <unistd.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>void catch_sig(int sig) // 参数:是捕捉的信号编号{pid_t pid;while(1){pid = waitpid(-1, NULL, WNOHANG);if(pid <= 0){break;}printf("died child_id=%d\n",pid);} }int main(){// 问题:父进程注册捕捉的时候,子进程已经死亡,这样信号根本捕捉不到// 重要思想:先屏蔽信号,再解除屏蔽// 这样:即使子进程先死,内核产生的信号也会被屏蔽掉,然后再解除屏蔽,信号就可以被顺利捕捉了// 父进程先设置屏蔽信号集,屏蔽SIGCHLD信号sigset_t proc; // 定义自定义信号集sigemptyset(&proc); // 第一步:清空自定义信号集,防止随机数干扰其他信号sigaddset(&proc, SIGCHLD); // 将 sigchld 信号 添加到自定义集合sigprocmask(SIG_BLOCK, &proc, NULL); // 通过 自定义信号集 设置 屏蔽信号集// 创建5个子进程int i = 0;for(i = 0 ;i < 5; i ++){pid_t pid = fork();if(pid == 0){break;}}// 此时,6个进程在运行if(i < 5){// 子进程printf("I am %d child, mypid=%d\n", i+1, getpid());}else if(i == 5){// 父进程逻辑 前期已经将信号屏蔽掉了,此时使用 sigaction 进行捕捉struct sigaction act;act.sa_flags = 0;act.sa_handler = catch_sig;sigemptyset(&act.sa_mask); // 不设置临时屏蔽信号sigaction(SIGCHLD, &act, NULL);// 注意:先注册捕捉,再解除屏蔽,顺序不能反sigprocmask(SIG_UNBLOCK, &proc, NULL);while(1){sleep(1); // 父进程一直存活,使子进程先执行return死亡}}return 0;}