python 多进程 避免僵尸进程,
1.前言之前在《unix环境高级编程》第八章看进程的时候提到了孤儿进程和僵尸进程,这两个概念一直很模糊。今天被问到孤儿进程和僵尸进程是什么,会带来什么问题,如何解决。只停留在概念上,为自己没有深入而感到惭愧。晚上google了一下,又参考了一遍APUE,认真总结了一下,加深了理解。
2.基本概念我们知道,在unix/linux中,一般情况下,子进程是由父进程创建的,子进程在创建一个新进程。子进程的结束和父进程的运行是异步过程,即父进程永远无法预测子进程何时结束。当一个进程完成其工作终止时,其父进程需要调用wait()或waitpid()系统调用来获取子进程的终止状态。
孤立进程:如果一个父进程退出,而它的一个或多个子进程仍在运行,这些子进程将成为孤立进程。孤儿将被init进程(进程号1)收养,init进程将收集它们的状态。
僵尸:一个进程使用fork创建一个子进程。如果子进程退出,而父进程没有调用wait或waitpid来获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这个过程被称为僵尸过程。
3.问题和危害unix提供了一种机制,保证只要父进程在最后想知道子进程的状态信息,就能得到。这个机制是:当每个进程退出时,内核释放该进程的所有资源,包括打开的文件、占用的内存等。但是仍然为它保留了一些信息(包括进程号、进程ID、退出状态、进程的终止状态、运行时间、进程占用的CPU时间等。).直到父进程通过wait/waitpid得到它,它才被释放。但这导致了问题。如果进程不调用wait/waitpid,预留的信息不会被释放,它的进程号会一直被占用。但是,系统可以使用的进程号的数量是有限的。如果生成了大量死进程,系统将无法生成新进程,因为没有可用的进程号。这就是僵尸进程的危害,应该避免。
孤儿进程是没有父进程的进程,所以孤儿进程就落在了init进程身上,init进程就像一个民政局,负责处理孤儿进程的善后事宜。每当出现一个孤儿进程,内核就将孤儿进程的父进程设置为init,init进程会循环等待()其已经退出的子进程。这样,当一个孤儿进程悲惨地结束它的生命周期时,init进程将代表党和政府处理它的所有善后事宜。因此,孤儿进程不会造成任何伤害。
任何子进程(除了init)在exit()之后都不会立即消失,而是留下一个数据结构叫僵尸进程,等待父进程处理。这是每个子流程最后都要经历的阶段。如果子进程在exit()后面,父进程没时间处理,那么用ps命令可以看到子进程的状态是“Z”。如果父进程能及时处理,用ps命令看到子进程的僵尸状态可能就来不及了,但这并不代表子进程不经历僵尸状态。如果父进程在子进程结束前退出,子进程将由init接管。Init将把处于僵死状态的子进程作为父进程来处理。
僵尸危险场景:
例如,有一个进程会定期产生一个子进程。这个子进程需要做的事情很少,做完该做的事情就退出了。所以这个子进程的生命周期很短。而父进程只生成新的子进程,至于子进程退出后会发生什么,它视而不见。这样,系统运行一段时间后,系统中就会出现很多死进程。如果你用ps命令检查它们,你会严格地说,僵尸进程并不是问题的根源,罪魁祸首是产生大量僵尸进程的父进程。所以,当我们寻求如何消灭系统中的大量僵尸进程时,答案就是射杀产生大量僵尸进程的元凶(即通过KILL发送SIGTERM或SIGKILL信号)。罪魁祸首进程被枪毙后,其产生的僵尸进程就成了孤儿进程。这些孤儿进程会被init进程接管,init进程会等待()这些孤儿进程,释放它们所占用的系统进程表中的资源。这样,这些僵尸孤儿进程就可以留下来了。
4.孤儿进程和僵尸进程测试孤儿进程测试程序如下:
#包含stdio.h
#包含stdlib.h
#包含错误号h
#包括unistd.h
int main()
{
pid _ t pid
//创建一个进程
PID=fork();
//创建失败。
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
//子进程
如果(pid==0)
{
printf(我是子进程。\ n’);
//输出进程ID和父进程ID
printf(pid: %d\tppid:%d\n ,getpid(),getppid());
printf(‘我会睡五秒钟。\ n’);
//睡眠5s,保证父进程先退出。
睡眠(5);
printf(pid: %d\tppid:%d\n ,getpid(),getppid());
printf(子进程退出。\ n’);
}
//父进程
其他
{
printf(我是父进程。\ n’);
//父进程休眠1s,保证子进程输出进程id。
睡眠(1);
printf(父进程退出。\ n’);
}
返回0;
}测试结果如下:
僵尸测试程序如下:
#包含stdio.h
#包括unistd.h
#包含错误号h
#包含stdlib.h
int main()
{
pid _ t pid
PID=fork();
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
else if (pid==0)
{
printf(我是子进程。我退出。\ n’);
退出(0);
}
printf(我是父进程。我就睡两秒\ n’);
//等待子进程先退出
睡眠(2);
//输出进程信息
system(ps -o pid,ppid,state,tty,command );
printf(父进程正在退出。\ n’);
返回0;
}测试结果如下:
僵尸测试二:父进程循环创建子进程,子进程退出,产生多个僵尸进程。该过程如下:
#包含stdio.h
#包含stdlib.h
#包括unistd.h
#包含错误号h
int main()
{
pid _ t pid
//在循环中创建子进程
while(1)
{
PID=fork();
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
else if (pid==0)
{
printf(我是子进程。\ n我要退出。\ n’);
//子进程退出,成为僵尸进程。
退出(0);
}
其他
{
//父进程休眠20秒,继续创建子进程。
睡眠(20);
继续;
}
}
返回0;
}程序测试结果如下:
5.僵尸进程的解决方案(1)通过信号机制在子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait来处理僵尸进程。测试程序如下:
#包含stdio.h
#包括unistd.h
#包含错误号h
#包含stdlib.h
#包含信号. h
静态void SIG _ child(int signo);
int main()
{
pid _ t pid
//创建捕获子进程退出信号。
signal(SIGCHLD,SIG _ child);
PID=fork();
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
else if (pid==0)
{
printf(我是子进程,pid id %d,我正在退出。\n ,getpid());
退出(0);
}
printf(我是父进程。我就睡两秒\ n’);
//等待子进程先退出
睡眠(2);
//输出进程信息
system(ps -o pid,ppid,state,tty,command );
printf(父进程正在退出。\ n’);
返回0;
}
静态void sig_child(int signo)
{
pid _ t pid
int stat
//处理僵尸进程
while ((pid=waitpid(-1,stat,WNOHANG)) 0)
printf(子级%d已终止。\n ,PID);
}测试结果如下:
(2)叉两下
055-79000第8.6节非常详细。原理是让子进程成为孤儿进程,让它的父进程成为init进程,通过它可以处理僵尸进程。测试程序如下:
#包含stdio.h
#包含stdlib.h
#包括unistd.h
#包含错误号h
int main()
{
pid _ t pid
//创建第一个子进程
PID=fork();
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
//第一个子进程
else if (pid==0)
{
//子进程重新创建子进程
printf(我是第一个子进程. pid:%d\tppid:%d\n ,getpid(),getppid());
PID=fork();
如果(pid 0)
{
perror(fork错误:);
出口(1);
}
//第一个子进程退出
else if (pid 0)
{
printf(第一个进程退出。\ n’);
退出(0);
}
//第二个子进程
//休眠3s,确保第一个子进程退出,这样第二个子进程的父进程就在init进程中了。
睡眠(3);
printf(我是第二个子进程. pid: %d\tppid:%d\n ,getpid(),getppid());
退出(0);
}
//父进程处理第一个子进程的退出
if (waitpid(pid,NULL,0)!=pid)
{
perror(waitepid错误:);
出口(1);
}
退出(0);
返回0;
}测试结果如下图所示:
6.参考《Unix 环境高级编程》,第8章
http://www.rosoo.net/a/201109/15071.html
http://blog.chinaunix.net/uid-1829236-id-3166986.html
http://forkhope.diandian.com/post/2012-10-01/40040574200
涉及
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。