免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 11318 | 回复: 22
打印 上一主题 下一主题

执行system后产生defunct,高手进来分析下 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-07-22 15:53 |只看该作者 |倒序浏览
程序中通过system()调用另一个可执行程序, 如:
if (0 != system("./exe_process args"))
{
     DEBUGLOG("error");
}

但在长期运行中经常发现出现 exe_process 的defunct进程, 看了下system的源码, 无非就是fork, exec, waitpid

不明白为什么会出现僵尸进程

补充: 此程序运行时内存可能有限, 不知道是否有影响

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
2 [报告]
发表于 2010-07-22 16:05 |只看该作者
能把源码贴一下吗?

论坛徽章:
0
3 [报告]
发表于 2010-07-22 16:18 |只看该作者
源码几乎就是我上面贴的样子, 就是在一个函数里调用system,没什么特别的

论坛徽章:
84
每日论坛发贴之星
日期:2015-12-29 06:20:00每日论坛发贴之星
日期:2016-01-16 06:20:00每周论坛发贴之星
日期:2016-01-17 22:22:00程序设计版块每日发帖之星
日期:2016-01-20 06:20:00每日论坛发贴之星
日期:2016-01-20 06:20:00程序设计版块每日发帖之星
日期:2016-01-21 06:20:00每日论坛发贴之星
日期:2016-01-21 06:20:00程序设计版块每日发帖之星
日期:2016-01-23 06:20:00程序设计版块每日发帖之星
日期:2016-01-31 06:20:00数据库技术版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-14 06:20:00
4 [报告]
发表于 2010-07-22 17:52 |只看该作者
僵尸进程产生的条件你知道吗??

论坛徽章:
0
5 [报告]
发表于 2010-07-22 20:25 |只看该作者
感谢关注

所谓僵尸进程,应该是子进程退出了, 而父进程并没有处理子进程的退出(waitpid或SIGCHLD等), 导致子进程的部分资源没有完全销毁而产生的吧

理解不对的地方还望指教

我的问题是, system的源码里是处理了子进程的推出的, 不明白什么情况下会产生僵尸

论坛徽章:
0
6 [报告]
发表于 2010-07-22 22:26 |只看该作者
两次fork执行你的exe

论坛徽章:
0
7 [报告]
发表于 2010-07-22 22:29 |只看该作者

  1. int startProc(const struct proc_struct* proc)
  2. {
  3.     if(!proc)
  4.         {
  5.                 return 0;
  6.         }
  7.         int pid = fork();
  8.         if(pid == 0)
  9.         {
  10.                 char*szParam[] = {proc->cmdline, proc->param, NULL};
  11.                 pid = fork();
  12.                 if(pid == 0)
  13.                 {
  14.                         execvp(proc->cmdline, szParam);
  15.                         exit(0);
  16.                 }else
  17.                 {
  18.                         exit(0);
  19.                 }
  20.                
  21.         }else
  22.         {
  23.                 wait(NULL);
  24.                 return 1;               
  25.         }       
  26. }
复制代码
http://linux.chinaunix.net/bbs/thread-1021030-1-1.html

论坛徽章:
0
8 [报告]
发表于 2010-07-23 08:54 |只看该作者
感谢楼上解答

其实我的本意是想知道为什么system会产生僵尸进程, 比如有人碰到过、或者能从原理上讲明白

当然如果解决不了的话可能会考虑改为fork两次

论坛徽章:
0
9 [报告]
发表于 2010-07-23 10:11 |只看该作者
本帖最后由 duanjigang 于 2010-07-23 10:21 编辑
感谢楼上解答

其实我的本意是想知道为什么system会产生僵尸进程, 比如有人碰到过、或者能从原理上讲明白 ...
morris2600 发表于 2010-07-23 08:54


首先你可以看下《linux内核设计与实现》大概前几章,有一章讲这个的。另外,下面
这篇文章说的也很好。
http://hi.baidu.com/kobetec/blog ... dca883e950cdf4.html
怎样避免产生僵尸进程2008-02-20 17:09怎样避免产生僵尸进程
摘录于: <<Advanced Programming in the UNIX&reg; Environment: Second Edition>> By W. Richard Stevens, Stephen
1.什么是僵尸进程?
In UNIX System terminology, a process that has terminated,but whose

parent has not yet waited for it, is called a zombie.

在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,

那么他将变成一个僵尸进程.

但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程,

因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,

看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init

来接管他,成为他的父进程,从而保证每个进程都会有一个父进程.

而Init进程会自动wait 其子进程,因此被Init接管的所有进程都不会变成僵尸进程.

2. 僵尸进程的危害
由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程

到底什么时候结束. 那么不会因为父进程太忙来不及waid子进程,或者说不知道

子进程什么时候结束,而丢失子进程结束时的状态信息呢?

不会.因为UNIX提供了一种机制可以保证 只要父进程想知道子进程结束时的状态信息,

就可以得到. 这种机制就是:

在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等.

但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination

status of the process,运行时间the amount of CPU time taken by the process等),

直到父进程通过wait / waitpid来取时才释放.

但这样就导致了问题,如果你进程不调用wait / waitpid的话, 那么保留的那段信息就不会

释放,其进程号就会一定被占用,但是系统所能使用的进程号是有限的,如果大量的产生

僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程.

此即为僵尸进程的危害,应当避免.

3.僵尸进程的避免
1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起

2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,

父进程会收到该信号,可以在handler中调用wait回收


3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)

通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,

并不再给父进程发送信号

4. 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一

个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收

还要自己做。 下面就是Stevens给的采用两次folk避免僵尸进程的示例.

Example
Recall our discussion in Section 8.5 about zombie processes. If we want to write a process so that it forks a child but we don't want to wait for the child to complete and we don't want the child to become a zombie until we terminate, the trick is to call fork twice. The program in Figure 8.8 does this.

We call sleep in the second child to ensure that the first child terminates before printing the parent process ID. After a fork, either the parent or the child can continue executing; we never know which will resume execution first. If we didn't put the second child to sleep, and if it resumed execution after the fork before its parent, the parent process ID that it printed would be that of its parent, not process ID 1.

  1. #include "apue.h"
  2. #include <sys/wait.h>

  3. int
  4. main(void)
  5. ...{
  6.      pid_t    pid;

  7.     if ((pid = fork()) < 0) ...{
  8.          err_sys("fork error");
  9.      } else if (pid == 0) ...{     /**//* first child */
  10.         if ((pid = fork()) < 0)
  11.              err_sys("fork error");
  12.         else if (pid > 0)
  13.              exit(0);    /**//* parent from second fork == first child */
  14.         /**//*
  15.           * We're the second child; our parent becomes init as soon
  16.           * as our real parent calls exit() in the statement above.
  17.           * Here's where we'd continue executing, knowing that when
  18.           * we're done, init will reap our status.
  19.          */
  20.          sleep(2);
  21.          printf("second child, parent pid = %d ", getppid());
  22.          exit(0);
  23.      }
  24.    
  25.     if (waitpid(pid, NULL, 0) != pid)  /**//* wait for first child */
  26.          err_sys("waitpid error");

  27.     /**//*
  28.       * We're the parent (the original process); we continue executing,
  29.       * knowing that we're not the parent of the second child.
  30.      */
  31.      exit(0);
  32. }

复制代码

论坛徽章:
0
10 [报告]
发表于 2010-07-23 10:13 |只看该作者
本帖最后由 duanjigang 于 2010-07-23 10:16 编辑

根据理论我们做个测试的例子。
子进程要执行的程序test_prog

  1. //test.c
  2. #include <stdio.h>
  3. int main()
  4. {
  5.         int i = 0;
  6.         for (i = 0 ; i < 10; i++)
  7.         {
  8.                 printf ("child time %d\n", i+1);
  9.                 sleep (1);
  10.         }
  11.         return 0;
  12. }
复制代码
父进程father的代码father.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. int main()
  6. {
  7.         int pid = fork ();
  8.         if (pid == 0)
  9.         {
  10.                 system ("./test_prog");
  11.                 _exit (0);
  12.         }else
  13.         {
  14.                 int i = 0;
  15.                 /*
  16.                                 int status = 0;
  17.                 while (!waitpid(pid, &status, WNOHANG))
  18.                 {
  19.                         printf ("father waiting%d\n", ++i);
  20.                         sleep (1);
  21.                 }*/
  22.                 while (1)
  23.                 {
  24.                         printf ("father waiting over%d\n", ++i);
  25.                         sleep (1);
  26.                 }
  27.                 return 0;
  28.         }

  29. }
复制代码
执行./father,当子进程退出后,由于父进程没有对它的退出进行关注,会出现僵尸进程

  1. 20786 pts/0    00:00:00 father
  2. 20787 pts/0    00:00:00 father <defunct>
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP