国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 操作系統(tǒng) > 正文

孤兒進程與僵尸進程[總結(jié)]

2024-06-28 16:00:47
字體:
供稿:網(wǎng)友

1、前言

  之前在看《unix環(huán)境高級編程》第八章進程時候,提到孤兒進程和僵尸進程,一直對這兩個概念比較模糊。今天被人問到什么是孤兒進程和僵尸進程,會帶來什么問題,怎么解決,我只停留在概念上面,沒有深入,倍感慚愧。晚上回來google了一下,再次參考APUE,認真總結(jié)一下,加深理解。

2、基本概念

  我們知道在unix/linux中,正常情況下,子進程是通過父進程創(chuàng)建的,子進程在創(chuàng)建新的進程。子進程的結(jié)束和父進程的運行是一個異步過程,即父進程永遠無法預(yù)測子進程 到底什么時候結(jié)束。 當一個 進程完成它的工作終止之后,它的父進程需要調(diào)用wait()或者waitpid()系統(tǒng)調(diào)用取得子進程的終止狀態(tài)。

  孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養(yǎng),并由init進程對它們完成狀態(tài)收集工作。

  僵尸進程:一個進程使用fork創(chuàng)建子進程,如果子進程退出,而父進程并沒有調(diào)用wait或waitpid獲取子進程的狀態(tài)信息,那么子進程的進程描述符仍然保存在系統(tǒng)中。這種進程稱之為僵死進程。

3、問題及危害

  unix提供了一種機制可以保證只要父進程想知道子進程結(jié)束時的狀態(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來取時才釋放。 但這樣就導(dǎo)致了問題,如果進程不調(diào)用wait / waitpid的話, 那么保留的那段信息就不會釋放,其進程號就會一直被占用,但是系統(tǒng)所能使用的進程號是有限的,如果大量的產(chǎn)生僵死進程,將因為沒有可用的進程號而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進程. 此即為僵尸進程的危害,應(yīng)當避免。

  孤兒進程是沒有父進程的進程,孤兒進程這個重任就落到了init進程身上,init進程就好像是一個民政局,專門負責處理孤兒進程的善后工作。每當出現(xiàn)一個孤兒進程的時候,內(nèi)核就把孤 兒進程的父進程設(shè)置為init,而init進程會循環(huán)地wait()它的已經(jīng)退出的子進程。這樣,當一個孤兒進程凄涼地結(jié)束了其生命周期的時候,init進程就會代表黨和政府出面處理它的一切善后工作。因此孤兒進程并不會有什么危害。

  任何一個子進程(init除外)在exit()之后,并非馬上就消失掉,而是留下一個稱為僵尸進程(Zombie)的數(shù)據(jù)結(jié)構(gòu),等待父進程處理。這是每個 子進程在結(jié)束時都要經(jīng)過的階段。如果子進程在exit()之后,父進程沒有來得及處理,這時用ps命令就能看到子進程的狀態(tài)是“Z”。如果父進程能及時 處理,可能用ps命令就來不及看到子進程的僵尸狀態(tài),但這并不等于子進程不經(jīng)過僵尸狀態(tài)。  如果父進程在子進程結(jié)束之前退出,則子進程將由init接管。init將會以父進程的身份對僵尸狀態(tài)的子進程進行處理。

  僵尸進程危害場景:

  例如有個進程,它定期的產(chǎn) 生一個子進程,這個子進程需要做的事情很少,做完它該做的事情之后就退出了,因此這個子進程的生命周期很短,但是,父進程只管生成新的子進程,至于子進程 退出之后的事情,則一概不聞不問,這樣,系統(tǒng)運行上一段時間之后,系統(tǒng)中就會存在很多的僵死進程,倘若用ps命令查看的話,就會看到很多狀態(tài)為Z的進程。 嚴格地來說,僵死進程并不是問題的根源,罪魁禍首是產(chǎn)生出大量僵死進程的那個父進程。因此,當我們尋求如何消滅系統(tǒng)中大量的僵死進程時,答案就是把產(chǎn)生大 量僵死進程的那個元兇槍斃掉(也就是通過kill發(fā)送SIGTERM或者SIGKILL信號啦)。槍斃了元兇進程之后,它產(chǎn)生的僵死進程就變成了孤兒進 程,這些孤兒進程會被init進程接管,init進程會wait()這些孤兒進程,釋放它們占用的系統(tǒng)進程表中的資源,這樣,這些已經(jīng)僵死的孤兒進程 就能瞑目而去了。

3、孤兒進程和僵尸進程測試

孤兒進程測試程序如下所示:

復(fù)制代碼
 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <errno.h> 4 #include <unistd.h> 5  6 int main() 7 { 8     pid_t pid; 9     //創(chuàng)建一個進程10     pid = fork();11     //創(chuàng)建失敗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和父進程ID22         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     else31     {32         printf("I am father process./n");33         //父進程睡眠1s,保證子進程輸出進程id34         sleep(1);35         printf("father process is  exited./n");36     }37     return 0;38 }復(fù)制代碼

測試結(jié)果如下:

僵尸進程測試程序如下所示:

復(fù)制代碼
 1 #include <stdio.h> 2 #include <unistd.h> 3 #include <errno.h> 4 #include <stdlib.h> 5  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 }復(fù)制代碼

測試結(jié)果如下所示:

僵尸進程測試2:父進程循環(huán)創(chuàng)建子進程,子進程退出,造成多個僵尸進程,程序如下所示:

復(fù)制代碼
 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <errno.h> 5  6 int main() 7 { 8     pid_t  pid; 9     //循環(huán)創(chuàng)建子進程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         else25         {26             //父進程休眠20s繼續(xù)創(chuàng)建子進程27             sleep(20);28             continue;29         }30     }31     return 0;32 }復(fù)制代碼

程序測試結(jié)果如下所示:

4、僵尸進程解決辦法

(1)通過信號機制

  子進程退出時向父進程發(fā)送SIGCHILD信號,父進程處理SIGCHILD信號。在信號處理函數(shù)中調(diào)用wait進行處理僵尸進程。測試程序如下所示:

復(fù)制代碼
 1 #include <stdio.h> 2 #include <unistd.h> 3 #include <errno.h> 4 #include <stdlib.h> 5 #include <signal.h> 6  7 static void sig_child(int signo); 8  9 int main()10 {11     pid_t pid;12     //創(chuàng)建捕捉子進程退出信號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 }復(fù)制代碼

測試結(jié)果如下所示:

(2)fork兩次  《Unix 環(huán)境高級編程》8.6節(jié)說的非常詳細。原理是將子進程成為孤兒進程,從而其的父進程變?yōu)閕nit進程,通過init進程可以處理僵尸進程。測試程序如下所示:

復(fù)制代碼
 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <errno.h> 5  6 int main() 7 { 8     pid_t  pid; 9     //創(chuàng)建第一個子進程10     pid = fork();11     if (pid < 0)12     {13         perror("fork error:");14         exit(1);15     }16     //第一個子進程17     else if (pid == 0)18     {19         //子進程再創(chuàng)建子進程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 }復(fù)制代碼

測試結(jié)果如下圖所示:

5、參考資料

《unix環(huán)境高級編程》第八章

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

冷靜思考,勇敢面對,把握未來!
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 桓仁| 噶尔县| 望都县| 方山县| 桐庐县| 临沂市| 交口县| 大田县| 大同县| 新龙县| 蒙城县| 平顶山市| 长白| 会东县| 万宁市| 元阳县| 茌平县| 高州市| 宜兰市| 宜兴市| 延边| 扶沟县| 东乌珠穆沁旗| 怀宁县| 石首市| 宜州市| 朝阳市| 龙州县| 廉江市| 横峰县| 武陟县| 花垣县| 常德市| 宁陵县| 额尔古纳市| 万荣县| 长泰县| 平乡县| 高要市| 新乡市| 万载县|