僵尸进程的产生
通俗的讲就是子进程死了,但是父进程还没有给它收尸,此时子进程就成了僵尸进程。
所谓的子进程死了,实际就是指子进程的退出,包括调用exit时的正常退出,或者被kill命令用信号查杀后的异常退出。
那么父进程如何给子进程收尸呢?在父进程中调用wait或waitpid接收子进程退出的状态,清理掉子进程的task_struct,释放子进程的PID。
僵尸进程的处理
子进程一旦成为了僵尸进程后就无法通过KILL来处理,是无法被杀死的,这时候可以通过杀死僵尸进程的父进程的方法来清理掉子进程。
父进程先结束,也就是父进程被杀死了,子进程依然存活,此时子进程被托管给init进程,由init进程回收子进程。这种情况下的子进程称为孤儿进程。
简单的代码验证
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
pid_t pid, wait_pid;
int status;
pid = fork(); //创建一个子进程
if(pid == -1){
printf("create new process failed \n");
exit(1);
}else if(pid == 0){
printf("child process id :%ld \n",(long)getpid());
pause(); //令子进程进入睡眠状直到信号被中断
exit(0);
}else{
printf("parent process id : %ld\n",(long)getpid());
#if 1
while(1);
#else
do{
wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);
//WIFEXITED 非0 表示进程正常结束
//WEXITSTATUS 获取进程退出状态exit的参数
//WIFSIGNALED 非0 表示进程异常结束
//WTERMSIG(staus) 获取进程退出的信号编号
if(WIFEXITED(status))
printf("child procees:%d is exit by %d \n",pid,WEXITSTATUS(status));
if(WIFSIGNALED(status))
printf("child procees:%d is killed by signal %d \n",pid,WTERMSIG(status));
}while(!WIFEXITED(status) && !WIFSIGNALED(status));
exit(0);
#endif
}
}
上述代码编译 gcc test1.c -pthread -o test,然后运行test,结果如下。
ps au查看进程状态,可以看到可以看到父进程60305,子进程60306。
此时此时选择用kill -2 60306,杀死子进程60306,然后ps au查看所有进程。
此时,60306成了僵尸进程,进程状态z+,而这时主进程转态R+,从代码中也可以看到主进程一直处于while循环中,没有任何的wait和waitpid操作。
修改宏定义为#if 0 ,然后编译运行test。得到如下运行结果。
使用ps au命令查看所有进程运行状态。可以看到父进程60250,子进程60251。
此时选择用kill -2 60251,杀死子进程60251后并没有使其称为僵尸进程。因为主进程中使用了waitpid处理了子进程,并在获取到子进程退出后,主进程也退出了。此处看到主进程获取到了子进程由于signal 2而产生的退出。
这时可以看到进程列表中,主进程和子进程都消失了。