在linux系统中,父进程通常会接收子进程SIGCHLD信号监测子进程是否退出,通过waitpid函数对子进程进行回收。但是实际应用过程中waitpid使用不当,会出现子进程成为僵尸进程。原因在于,SIGCHLD信号是不可靠信号,不可靠信号在Linux中不进行排队,只是放到一个缓冲区,一旦该信号解除阻塞则会立即被发送一次(不可靠信号会丢失)。
任何一个子进程(init除外)在exit()之后,并非马上就消失,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程回收。由于SIGCHLD信号的丢失,如果父进程不进行回收处理,子进程就会一直处于僵尸状态。
解决的办法有两个,一是在信号处理函数中,以非阻塞的方式调用waitpid,使用while循环,直到waitpid回收完所有等待回收的子进程。如下所示:
#include <sys/types.h>
#include <sys/wait.h>
signal(SIGCHLD,sigchld_handler);
void sigchld_handler(int signo)
{
pid_t pid;
int status = 0;
while((pid = waitpid(0,&status,WNOHANG)) > 0)
cout<<"pid "<<pid<<" exited !"<<endl;
}
需要注意的是,waitpid函数第三个参数需要设置为WNOHANG,这样才不会阻塞。
另外一种方式是在主线程或者创建线程中不停地while((pid = waitpid(0,&status,WNOHANG)) > 0),使得一有需要回收的子进程,就立马进行回收。
参考博客:
1.Linux–测试信号阻塞及排队
https://blog.csdn.net/Meteor_s/article/details/84999687?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
2.孤儿进程与僵尸进程[总结]
https://www.cnblogs.com/Anker/p/3271773.html