目录
1、孤儿进程
2、僵尸进程
定义:没有父进程的进程,unix环境中,当父进程比子进程先退出,子进程变为孤儿进程,linux环境中的1号进程 "/sbin/init" 接管系统中的所有的孤儿进程,因此此时子进程的父进程变为1号进程,代码如下:
...
if((pid = fork()) < 0)
{
printf("fork error\n");
}
else if(pid == 0)
{
printf("child:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
sleep(2);//等待父进程退出
printf("parent exit,child:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
exit(0);
}else{
printf("parent:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
sleep(1);
printf("parent exit\n");
exit(0);
}
...
运行结果:
root@localhost some_func]# ./orphan_process
parent:self_pid=6463,parent_pid=30749
child:self_pid=6464,parent_pid=6463
parent exit//父进程退出
parent exit,child:self_pid=6464,parent_pid=1//原父进程退出,孤儿进程被1号进程接管
小结:父进程退出后,由1号进程接管对应的子进程,因此孤儿进程对于系统是无害的。
定义:子进程先于父进程退出后,父进程并没有对子进程进行相应的回收处理。
代码如下:
...
if((pid = fork()) < 0)
{
printf("fork error\n");
}
else if(pid == 0)
{
printf("child:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
exit(0);
}else{
printf("parent:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
while(1){
sleep(3);
}
exit(0);
}
...
运行结果:
[root@localhost some_func]# ./zombie_process &
[2] 6564
[root@localhost some_func]# parent:self_pid=6564,parent_pid=30749
child:self_pid=6565,parent_pid=6564
[root@localhost some_func]# ps -ef | grep zombie_process
root 6564 30749 0 10:22 pts/3 00:00:00 ./zombie_process
root 6565 6564 0 10:22 pts/3 00:00:00 [zombie_process]
root 6567 30749 0 10:22 pts/3 00:00:00 grep zombie_process
[root@localhost some_func]# cat /proc/6565/status
Name: zombie_process
State: Z (zombie)
Tgid: 6565
Pid: 6565
PPid: 6564
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
如何避免:
1、产生僵尸进程后将父进程杀掉,所有资源被1号进程回收,因为无法直接通过 kill -9 杀死僵尸进程。
[root@localhost some_func]# ps -ef | grep zombie_process
root 6564 30749 0 10:22 pts/3 00:00:00 ./zombie_process
root 6565 6564 0 10:22 pts/3 00:00:00 [zombie_process]
root 6759 30749 0 10:54 pts/3 00:00:00 grep zombie_process
//无法直接杀死僵尸进程
[root@localhost some_func]# kill -9 6565
[root@localhost some_func]# ps -ef | grep zombie_process
root 6564 30749 0 10:22 pts/3 00:00:00 ./zombie_process
root 6565 6564 0 10:22 pts/3 00:00:00 [zombie_process]
root 6761 30749 0 10:54 pts/3 00:00:00 grep zombie_process
//杀死父进程曲线救国
[root@localhost some_func]# kill -9 6564
[root@localhost some_func]# ps -ef | grep zombie_process
root 6771 30749 0 10:55 pts/3 00:00:00 grep zombie_process
[2]+ Killed ./zombie_process
[root@localhost some_func]# ps -ef | grep zombie_process
root 6773 30749 0 10:55 pts/3 00:00:00 grep zombie_process
[root@localhost some_func]#
2、父进程中直接调用 wait/waitpid 回收子进程。
...
if((pid = fork()) < 0)
{
printf("fork error\n");
}
else if(pid == 0)
{
sleep(1);
printf("child:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
exit(0);
}else{
printf("parent:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
if(waitpid(pid,NULL,0) == -1)
{
printf("Child process recycled fail\n");
}else{
printf("Child process recycled successfully\n");
}
while(1){
sleep(3);
}
exit(0);
}
...
[root@localhost some_func]# ./zombie_process &
[2] 6872
[root@localhost some_func]# parent:self_pid=6872,parent_pid=30749
child:self_pid=6873,parent_pid=6872
Child process recycled successfully
[root@localhost some_func]# ps -ef | grep zombie_process
root 6872 30749 0 11:01 pts/3 00:00:00 ./zombie_process
root 6875 30749 0 11:01 pts/3 00:00:00 grep zombie_process
[root@localhost some_func]#
3、注册子进程退出信号量SIGCHLD的钩子,在钩子中调用wait/waitpid回收子进程。
#include
#include
#include
#include
void sigchld_handler(int signo);
pid_t pid;
int main()
{
//建立SIGCHLD信号(子进程退出信号)的处理函数
signal(SIGCHLD, sigchld_handler);
if((pid = fork()) < 0)
{
printf("fork error\n");
}
else if(pid == 0)
{
printf("child:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
sleep(5);
exit(0);
}else{
printf("parent:self_pid=%d,parent_pid=%d\n",getpid(),getppid());
while(1){
printf("parent running\n");
sleep(1);
}
exit(0);
}
}
void sigchld_handler(int signo)
{
if (signo != SIGCHLD)
{
printf("signo=%d,check fail\n",signo);
return;
}
printf("child exit signo=%d\n",signo);
if(waitpid(pid,NULL,0) == -1)
{
printf("Child process recycled fail\n");
}else{
printf("Child process recycled successfully");
}
return ;
}
[root@localhost some_func]# ./zombie_process
parent:self_pid=6921,parent_pid=30749
parent running
child:self_pid=6922,parent_pid=6921
parent running
parent running
parent running
parent running
child exit signo=17
Child process recycled successfullyparent running
parent running
parent running
parent running
parent running
parent running
^C
[root@localhost some_func]#
小结:从资源上讲,僵尸并不会占用什么系统资源,但是通常系统可以创建、管理的进程总数是有限的,如果有大量的僵尸进程占用着PID不干事,将会导致其它进程无法创建。从回收僵尸进程的方式讲,通过 杀死父进程间接回收或者在父进程直接调用waitpid(导致进程阻塞)都有一定的缺陷,通过注册SIGCHLD钩子处理无疑是最好的一种。