回收子進程——wait/waitpid 與 信號機制


孤兒/僵屍進程——回收子進程

參考博客:https://blog.csdn.net/qq_35396127/article/details/78725915

    :https://www.cnblogs.com/Anker/p/3271773.html

  在Linux下,子進程可由父進程創建,子進程也可以創建新的進程。但是父進程無法預測子進程的運行狀態,不知道子進程何時會結束。由此會產生孤兒進程與僵屍進程。所以當一個進程結束后,它的父進程需要調用wait(),waitpid()系統調用獲取子進程終止狀態,回收子進程。

  什么是孤兒進程與僵屍進程?

  孤兒進程:

  父進程先於子進程結束,則子進程失去父進程,子進程就會被init 進程收養,子進程就成為孤兒進程。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 
 5 int main(void)
 6 {
 7     pid_t pid;
 8     int i=0;
 9     //創建一個子進程
10     pid = fork();
11 
12     if(pid == -1)
13     {
14         perror("fork");
15         exit(1); //1:異常退出 0:正常退出
16     }
17     else if(pid>0)
18     {
19         printf("I am parent, my pid=%d\n",getpid());
20         sleep(4); //父進程運行4秒后結束
21         printf("---------parent going to die-----------\n");
22 
23     }
24     else
25     {
26         while(i<80)
27         {
28             //待父進程結束后會被init收養
29             printf("I am child, pid = %d, parentpid = %d\n",getpid(),getppid());
30             sleep(1);
31             i++;
32         }
33     }
34     return 0;
35 }

結果:

 

 有的Ubuntu版本,會設置user init 進程專門處理孤兒進程

 

 

 

 

僵屍進程:

  子進程終止,父進程未回收子進程的資源PCB,使其變成僵屍進程。

測試程序:

 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, I am exiting.\n");
18         exit(0);
19     }
20 
21     printf("I am parent,I will sleep 2s\n");
22     //等待子進程先退出
23     sleep(2);
24     //輸出進程信息
25     system("ps -o pid,ppid,state,tty,command");
26     printf("father process exiting\n");
27 
28     return 0;
29 }
30 
31 源自:https://www.cnblogs.com/Anker/p/3271773.html

結果:

 

 

  孤兒進程與僵屍進程的危害

  在Linux中,每個進程退出時,內核會釋放該進程所有資源,包括打開的文件,占用的內存等,但仍為之保留一定信息,包括:進程ID,退出狀態,運行時間等。直到父進程通過wait/waitpid來取時,才會釋放。因此,只要進程一直調用wait與waitpid,進程占用的資源就不會釋放,進程號也不會釋放,由於系統能使用的進程號是有限的,就可能因為大量僵屍進程占用進程號而不能產生新進程。當系統中產生大量僵屍進程時,應該把產生僵屍進程的父進程給殺死掉。可以通過kill發送SIGTERM或者SIGKILL信號,之后僵屍進程會因為沒了父進程變成孤兒,被init收養再釋放。

  對於孤兒進程,會被init進程收養,而且init進程會循環地wait()它收養的子進程。所以孤兒進程並無危害。

 

  通過信號機制解決僵屍進程

  子進程退出時會向父進程發送SIGCHLD信號,父進程調用信號處理函數,進而調用wait處理僵屍進程。測試程序:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <errno.h>
 4 #include <stdlib.h>
 5 #include <signal.h>
 6 
 7 static void handlefunc(int sig)
 8 {
 9     pid_t pid;
10     int   stat;
11 
12     //處理僵屍進程
13     //waitpid(-1:回收任一子進程,子進程結束狀態,不阻塞父進程)
14     //waitpid成功返回子進程pid
15     while((pid = waitpid(-1, &stat, WNOHANG))>0)
16         printf("child %d terminated. \n",pid);
17 }
18 
19 int main()
20 {
21     pid_t pid;
22     //創建signal,捕捉子進程退出信號
23     signal(SIGCHLD,handlefunc);
24     pid = fork();
25     if(pid<0)
26     {
27         perror("fork error:");
28         exit(1);
29     }
30     else if(pid == 0)
31     {
32         printf("I am chid, pid=%d. I exiting\n",getpid());
33         exit(0);
34     }
35     printf("I am parent. I sleep 3S\n");
36     //等待子進程退出
37     sleep(3);
38     //輸出進程信息
39     system("ps -o pid,ppid,state,tty,command");
40     printf("parent exiting");
41 
42     return 0;
43 
44 }

結果:僵屍進程消失

 

signal(SIGCLD,SIG_IGN);

因為並發服務器常常fork很多子進程,子進程終結之后需要服務器進程去wait清理資源。如果將此信號的處理方式設為忽略,可讓內核把僵屍子進程轉交給init進程去處理,省去了大量僵屍進程占用系統資源。

詳見:https://blog.csdn.net/u012317833/article/details/39253793

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM