公司网站去哪里做,hao123网址之家官网电脑版,wordpress免插件灯箱,大连工业大学宿舍1、前言 之前在看《unix环境高级编程》第八章进程时候#xff0c;提到孤儿进程和僵尸进程#xff0c;一直对这两个概念比较模糊。今天被人问到什么是孤儿进程和僵尸进程#xff0c;会带来什么问题#xff0c;怎么解决#xff0c;我只停留在概念上面#xff0c;没有深入提到孤儿进程和僵尸进程一直对这两个概念比较模糊。今天被人问到什么是孤儿进程和僵尸进程会带来什么问题怎么解决我只停留在概念上面没有深入倍感惭愧。晚上回来google了一下再次参考APUE认真总结一下加深理解。 2、基本概念 我们知道在unix/linux中正常情况下子进程是通过父进程创建的子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。 孤儿进程一个父进程退出而它的一个或多个子进程还在运行那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养并由init进程对它们完成状态收集工作。 僵尸进程一个进程使用fork创建子进程如果子进程退出而父进程并没有调用wait或waitpid获取子进程的状态信息那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。 3、问题及危害 unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放。 但这样就导致了问题如果进程不调用wait / waitpid的话 那么保留的那段信息就不会释放其进程号就会一直被占用但是系统所能使用的进程号是有限的如果大量的产生僵死进程将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害应当避免。 孤儿进程是没有父进程的进程孤儿进程这个重任就落到了init进程身上init进程就好像是一个民政局专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候内核就把孤 儿进程的父进程设置为init而init进程会循环地wait()它的已经退出的子进程。这样当一个孤儿进程凄凉地结束了其生命周期的时候init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。 任何一个子进程(init除外)在exit()之后并非马上就消失掉而是留下一个称为僵尸进程(Zombie)的数据结构等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后父进程没有来得及处理这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理可能用ps命令就来不及看到子进程的僵尸状态但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。 僵尸进程危害场景 例如有个进程它定期的产 生一个子进程这个子进程需要做的事情很少做完它该做的事情之后就退出了因此这个子进程的生命周期很短但是父进程只管生成新的子进程至于子进程 退出之后的事情则一概不闻不问这样系统运行上一段时间之后系统中就会存在很多的僵死进程倘若用ps命令查看的话就会看到很多状态为Z的进程。 严格地来说僵死进程并不是问题的根源罪魁祸首是产生出大量僵死进程的那个父进程。因此当我们寻求如何消灭系统中大量的僵死进程时答案就是把产生大 量僵死进程的那个元凶枪毙掉也就是通过kill发送SIGTERM或者SIGKILL信号啦。枪毙了元凶进程之后它产生的僵死进程就变成了孤儿进 程这些孤儿进程会被init进程接管init进程会wait()这些孤儿进程释放它们占用的系统进程表中的资源这样这些已经僵死的孤儿进程 就能瞑目而去了。 3、孤儿进程和僵尸进程测试 孤儿进程测试程序如下所示 1 #include stdio.h2 #include stdlib.h3 #include errno.h4 #include unistd.h5 6 int main()7 {8 pid_t pid;9 //创建一个进程
10 pid fork();
11 //创建失败
12 if (pid 0)
13 {
14 perror(fork error:);
15 exit(1);
16 }
17 //子进程
18 if (pid 0)
19 {
20 printf(I am the child process.\n);
21 //输出进程ID和父进程ID
22 printf(pid: %d\tppid:%d\n,getpid(),getppid());
23 printf(I will sleep five seconds.\n);
24 //睡眠5s保证父进程先退出
25 sleep(5);
26 printf(pid: %d\tppid:%d\n,getpid(),getppid());
27 printf(child process is exited.\n);
28 }
29 //父进程
30 else
31 {
32 printf(I am father process.\n);
33 //父进程睡眠1s保证子进程输出进程id
34 sleep(1);
35 printf(father process is exited.\n);
36 }
37 return 0;
38 } 测试结果如下 僵尸进程测试程序如下所示 1 #include stdio.h2 #include unistd.h3 #include errno.h4 #include stdlib.h5 6 int main()7 {8 pid_t pid;9 pid fork();
10 if (pid 0)
11 {
12 perror(fork error:);
13 exit(1);
14 }
15 else if (pid 0)
16 {
17 printf(I am child process.I am exiting.\n);
18 exit(0);
19 }
20 printf(I am father process.I will sleep two seconds\n);
21 //等待子进程先退出
22 sleep(2);
23 //输出进程信息
24 system(ps -o pid,ppid,state,tty,command);
25 printf(father process is exiting.\n);
26 return 0;
27 } 测试结果如下所示 僵尸进程测试2父进程循环创建子进程子进程退出造成多个僵尸进程程序如下所示 1 #include stdio.h2 #include stdlib.h3 #include unistd.h4 #include errno.h5 6 int main()7 {8 pid_t pid;9 //循环创建子进程
10 while(1)
11 {
12 pid fork();
13 if (pid 0)
14 {
15 perror(fork error:);
16 exit(1);
17 }
18 else if (pid 0)
19 {
20 printf(I am a child process.\nI am exiting.\n);
21 //子进程退出成为僵尸进程
22 exit(0);
23 }
24 else
25 {
26 //父进程休眠20s继续创建子进程
27 sleep(20);
28 continue;
29 }
30 }
31 return 0;
32 } 程序测试结果如下所示 4、僵尸进程解决办法 1通过信号机制 子进程退出时向父进程发送SIGCHILD信号父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示 1 #include stdio.h2 #include unistd.h3 #include errno.h4 #include stdlib.h5 #include signal.h6 7 static void sig_child(int signo);8 9 int main()
10 {
11 pid_t pid;
12 //创建捕捉子进程退出信号
13 signal(SIGCHLD,sig_child);
14 pid fork();
15 if (pid 0)
16 {
17 perror(fork error:);
18 exit(1);
19 }
20 else if (pid 0)
21 {
22 printf(I am child process,pid id %d.I am exiting.\n,getpid());
23 exit(0);
24 }
25 printf(I am father process.I will sleep two seconds\n);
26 //等待子进程先退出
27 sleep(2);
28 //输出进程信息
29 system(ps -o pid,ppid,state,tty,command);
30 printf(father process is exiting.\n);
31 return 0;
32 }
33
34 static void sig_child(int signo)
35 {
36 pid_t pid;
37 int stat;
38 //处理僵尸进程
39 while ((pid waitpid(-1, stat, WNOHANG)) 0)
40 printf(child %d terminated.\n, pid);
41 } 测试结果如下所示 2fork两次 《Unix 环境高级编程》8.6节说的非常详细。原理是将子进程成为孤儿进程从而其的父进程变为init进程通过init进程可以处理僵尸进程。测试程序如下所示 1 #include stdio.h2 #include stdlib.h3 #include unistd.h4 #include errno.h5 6 int main()7 {8 pid_t pid;9 //创建第一个子进程
10 pid fork();
11 if (pid 0)
12 {
13 perror(fork error:);
14 exit(1);
15 }
16 //第一个子进程
17 else if (pid 0)
18 {
19 //子进程再创建子进程
20 printf(I am the first child process.pid:%d\tppid:%d\n,getpid(),getppid());
21 pid fork();
22 if (pid 0)
23 {
24 perror(fork error:);
25 exit(1);
26 }
27 //第一个子进程退出
28 else if (pid 0)
29 {
30 printf(first procee is exited.\n);
31 exit(0);
32 }
33 //第二个子进程
34 //睡眠3s保证第一个子进程退出这样第二个子进程的父亲就是init进程里
35 sleep(3);
36 printf(I am the second child process.pid: %d\tppid:%d\n,getpid(),getppid());
37 exit(0);
38 }
39 //父进程处理第一个子进程退出
40 if (waitpid(pid, NULL, 0) ! pid)
41 {
42 perror(waitepid error:);
43 exit(1);
44 }
45 exit(0);
46 return 0;
47 } 测试结果如下图所示 5、参考资料 《unix环境高级编程》第八章 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 http://blog.csdn.net/metasearch/article/details/2498853 http://blog.csdn.net/yuwenliang/article/details/6770750 冷静思考勇敢面对把握未来