亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標題: 執(zhí)行system后產(chǎn)生defunct,高手進來分析下 [打印本頁]

作者: morris2600    時間: 2010-07-22 15:53
標題: 執(zhí)行system后產(chǎn)生defunct,高手進來分析下
程序中通過system()調用另一個可執(zhí)行程序, 如:
if (0 != system("./exe_process args"))
{
     DEBUGLOG("error");
}

但在長期運行中經(jīng)常發(fā)現(xiàn)出現(xiàn) exe_process 的defunct進程, 看了下system的源碼, 無非就是fork, exec, waitpid

不明白為什么會出現(xiàn)僵尸進程

補充: 此程序運行時內(nèi)存可能有限, 不知道是否有影響
作者: openspace    時間: 2010-07-22 16:05
能把源碼貼一下嗎?
作者: morris2600    時間: 2010-07-22 16:18
源碼幾乎就是我上面貼的樣子, 就是在一個函數(shù)里調用system,沒什么特別的
作者: yjh777    時間: 2010-07-22 17:52
僵尸進程產(chǎn)生的條件你知道嗎??
作者: morris2600    時間: 2010-07-22 20:25
感謝關注

所謂僵尸進程,應該是子進程退出了, 而父進程并沒有處理子進程的退出(waitpid或SIGCHLD等), 導致子進程的部分資源沒有完全銷毀而產(chǎn)生的吧

理解不對的地方還望指教

我的問題是, system的源碼里是處理了子進程的推出的, 不明白什么情況下會產(chǎn)生僵尸
作者: duanjigang    時間: 2010-07-22 22:26
兩次fork執(zhí)行你的exe
作者: duanjigang    時間: 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
作者: morris2600    時間: 2010-07-23 08:54
感謝樓上解答

其實我的本意是想知道為什么system會產(chǎn)生僵尸進程, 比如有人碰到過、或者能從原理上講明白

當然如果解決不了的話可能會考慮改為fork兩次
作者: duanjigang    時間: 2010-07-23 10:11
本帖最后由 duanjigang 于 2010-07-23 10:21 編輯
感謝樓上解答

其實我的本意是想知道為什么system會產(chǎn)生僵尸進程, 比如有人碰到過、或者能從原理上講明白 ...
morris2600 發(fā)表于 2010-07-23 08:54


首先你可以看下《linux內(nèi)核設計與實現(xiàn)》大概前幾章,有一章講這個的。另外,下面
這篇文章說的也很好。
http://hi.baidu.com/kobetec/blog ... dca883e950cdf4.html
怎樣避免產(chǎn)生僵尸進程2008-02-20 17:09怎樣避免產(chǎn)生僵尸進程
摘錄于: <<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 系統(tǒng)中,一個進程結束了,但是他的父進程沒有等待(調用wait / waitpid)他,

那么他將變成一個僵尸進程.

但是如果該進程的父進程已經(jīng)先結束了,那么該進程就不會變成僵尸進程,

因為每個進程結束的時候,系統(tǒng)都會掃描當前系統(tǒng)中所運行的所有進程,

看有沒有哪個進程是剛剛結束的這個進程的子進程,如果是的話,就由Init

來接管他,成為他的父進程,從而保證每個進程都會有一個父進程.

而Init進程會自動wait 其子進程,因此被Init接管的所有進程都不會變成僵尸進程.

2. 僵尸進程的危害
由于子進程的結束和父進程的運行是一個異步過程,即父進程永遠無法預測子進程

到底什么時候結束. 那么不會因為父進程太忙來不及waid子進程,或者說不知道

子進程什么時候結束,而丟失子進程結束時的狀態(tài)信息呢?

不會.因為UNIX提供了一種機制可以保證 只要父進程想知道子進程結束時的狀態(tài)信息,

就可以得到. 這種機制就是:

在每個進程退出的時候,內(nèi)核釋放該進程所有的資源,包括打開的文件,占用的內(nèi)存等.

但是仍然為其保留一定的信息(包括進程號the process ID,退出狀態(tài)the termination

status of the process,運行時間the amount of CPU time taken by the process等),

直到父進程通過wait / waitpid來取時才釋放.

但這樣就導致了問題,如果你進程不調用wait / waitpid的話, 那么保留的那段信息就不會

釋放,其進程號就會一定被占用,但是系統(tǒng)所能使用的進程號是有限的,如果大量的產(chǎn)生

僵死進程,將因為沒有可用的進程號而導致系統(tǒng)不能產(chǎn)生新的進程.

此即為僵尸進程的危害,應當避免.

3.僵尸進程的避免
1、父進程通過wait和waitpid等函數(shù)等待子進程結束,這會導致父進程掛起

2. 如果父進程很忙,那么可以用signal函數(shù)為SIGCHLD安裝handler,因為子進程結束后,

父進程會收到該信號,可以在handler中調用wait回收


3. 如果父進程不關心子進程什么時候結束,那么可以用signal(SIGCHLD, SIG_IGN)

通知內(nèi)核,自己對子進程的結束不感興趣,那么子進程結束后,內(nèi)核會回收,

并不再給父進程發(fā)送信號

4. 還有一些技巧,就是fork兩次,父進程fork一個子進程,然后繼續(xù)工作,子進程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. }

復制代碼

作者: duanjigang    時間: 2010-07-23 10:13
本帖最后由 duanjigang 于 2010-07-23 10:16 編輯

根據(jù)理論我們做個測試的例子。
子進程要執(zhí)行的程序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. }
復制代碼
執(zhí)行./father,當子進程退出后,由于父進程沒有對它的退出進行關注,會出現(xiàn)僵尸進程

  1. 20786 pts/0    00:00:00 father
  2. 20787 pts/0    00:00:00 father <defunct>
復制代碼

作者: duanjigang    時間: 2010-07-23 10:19
如果你把上面father.c中的waitpid的注釋打開,會出現(xiàn)如下現(xiàn)象。
子進程退出的一瞬間,父進程在sleep還未調用waitpid,這時會出現(xiàn)一個僵尸進程,但是馬上這個僵尸進程就消失了。因為waitpid調用,子進程的資源的到釋放了。
這時ps就只能看到一個正常的father進程了
作者: duanjigang    時間: 2010-07-23 10:23
另外你還可以讓子進程多跑一會兒,父進程立馬退出,就能看到子進程的父進程pid為1了,也就是被init進程接管了的現(xiàn)象,這些都能一一驗證。
或者兩次fork(),也就能看到對應的解釋了。
作者: morris2600    時間: 2010-07-23 10:36
回復 12# duanjigang


    謝謝你詳細的例子

   可能是我沒說清楚, 或者沒有把重點突出出來,

   我這邊出現(xiàn)的僵尸進程是system中調用的程序,也就是對應你的代碼中的test_prog變成了僵尸進程

   并且這個現(xiàn)象不是必然出現(xiàn)的。

   我的程序中并沒有先fork出子進程然后再執(zhí)行system, 只是直接調用system, 相當于這樣:

int  main()
{
       if (0 != system("./test_prog args"))
      {
             printf("error\n");
      }

       return 0;
}

然后偶然會發(fā)現(xiàn)test_prog變成了僵尸進程

我對照system的源碼分析過, 其實system里做的就是先fork一子進程, 在子進程里調用test_prog, 同時在父進程里調用waitpid,

所以從理論上分析system函數(shù)返回后不應該產(chǎn)生僵尸進程, 這才是我想問的
作者: duanjigang    時間: 2010-07-23 10:36
改一改,這個也不錯

  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.                 int cc = fork();
  11.                 if (cc == 0)
  12.                 {
  13.                                 system ("./test_prog");
  14.                                 printf ("son die..\n");
  15.                                 exit (0);
  16.                 }
  17.                 else
  18.                 {
  19.                                 int i = 0;
  20.                                 for (i = 0; i < 5; i++)
  21.                                 {
  22.                                         printf ("father running %d\n", ++i);
  23.                                         sleep (1);
  24.                                 }
  25.                                 printf ("father die..\n");
  26.                                 exit(0);
  27.                 }
  28.                 }else
  29.         {
  30.                 int i = 0;
  31.                        
  32.                 int status = 0;
  33.                 while (!waitpid(pid, &status, WNOHANG))
  34.                 {
  35.                         printf ("father waiting%d\n", ++i);
  36.                         sleep (1);
  37.                 }
  38.                 //wait(NULL);
  39.                 while (1)
  40.                 {
  41.                         printf ("gradpa waiting over%d\n", ++i);
  42.                         sleep (1);
  43.                 }
  44.                 return 0;
  45.         }

  46. }

復制代碼

作者: duanjigang    時間: 2010-07-23 10:37
回復  duanjigang


    謝謝你詳細的例子

   可能是我沒說清楚, 或者沒有把重點突出出來,

   ...
morris2600 發(fā)表于 2010-07-23 10:36



    喔,呵呵,那就看看你的system執(zhí)行的程序了,理解又偏差了{:3_183:}
作者: yjh777    時間: 2010-07-23 15:50
感謝關注

所謂僵尸進程,應該是子進程退出了, 而父進程并沒有處理子進程的退出(waitpid或SIGCHLD等), ...
morris2600 發(fā)表于 2010-07-22 20:25



哦,明白你的問題了; 以前用過system() 但沒碰到過這種問題。

什么環(huán)境? 建議 google system bug 看看吧,
作者: yjh777    時間: 2010-07-23 15:53
以前碰到過一個bash的bug,特定情況下bash core掉了;

system 默認是啟動一個默認 shell 來解釋執(zhí)行命令,難道,,   純屬猜測你還是google吧

good luck
作者: yjh777    時間: 2010-07-23 16:13
system 執(zhí)行的程序的直接父進程是shell進程,看看這個shell的類型、版本吧,,
作者: yjh777    時間: 2010-07-23 23:05
程序中通過system()調用另一個可執(zhí)行程序, 如:
if (0 != system("./exe_process args")
{
     DE ...
morris2600 發(fā)表于 2010-07-22 15:53


忘了問了,你的exe_process程序本身里面有沒有fork之類的動作,這也是要考慮的一個問題,,
作者: freesoftsomuch    時間: 2010-07-24 15:14
是不是你這個父進程了sleep 語句或 wait語句呢???
作者: linux初學三月    時間: 2010-07-25 08:54
一般都不會產(chǎn)生僵尸進程吧,因為init進程一直在守護等待它
作者: lanying_wzw    時間: 2010-07-25 11:33
system()一般是通過“sh -c”來執(zhí)行程序的,有可能sh異常退出,或者你的主程序里有fork(),子進程執(zhí)行的快,把system()里的waitpid()給中斷了?
作者: 0vk0    時間: 2010-07-25 19:54
子進程退出的狀態(tài)無法回收資源,這樣的進程就叫僵尸進程,也KILL不掉




歡迎光臨 Chinaunix (http://www.72891.cn/) Powered by Discuz! X3.2