SIGCHLD信号产生的条件

使用SIGCHLD信号解决僵尸进程问题
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>
void myFun(int num) {
printf("捕捉到的信号 :%d\\n", num);
// 回收子进程PCB的资源
// 使用wait()的问题:
// - 如果直接使用wait():由于常规信号不可排队的特性,使得部分SIGCHLD信号被丢弃
// - 如果循环调用wait():则父进程会一直阻塞在回调函数中
// while(1) {
// wait(NULL);
// }
while(1) {
// waitpid 设置非阻塞
int ret = waitpid(-1, NULL, WNOHANG);
if(ret > 0) {
printf("child die , pid = %d\\n", ret);
} else if(ret == 0) {
// 说明还有子进程活着,返回父进程
break;
} else if(ret == -1) {
// 没有子进程了。返回父进程
break;
}
}
}
int main() {
// 提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程很快结束,父进程还没有注册完信号捕捉
// 这种情况会发生段错误
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, NULL);
// 创建一些子进程
pid_t pid;
for(int i = 0; i < 20; i++) {
pid = fork();
if(pid == 0) {
break;
}
}
if(pid > 0) {
// 父进程
// 捕捉子进程死亡时发送的SIGCHLD信号
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = myFun;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD, &act, NULL);
// 注册完信号捕捉以后,解除阻塞
sigprocmask(SIG_UNBLOCK, &set, NULL);
while(1) {
printf("parent process pid : %d\\n", getpid());
sleep(2);
}
} else if( pid == 0) {
// 子进程
printf("child process pid : %d\\n", getpid());
}
return 0;
}