殭屍程式,孤兒程式

audience_fzn發表於2018-08-10

Z(zombie)——殭屍程式

  • 殭屍狀態是一個比較特殊的狀態,當程式退出並且父程式沒有讀取到子程式退出的返回程式碼時,就會產生殭屍程式
  • 殭屍程式會以終止狀態保持在程式表中,並且一致在等待父程式讀取退出狀態程式碼
  • 所以,子程式退出,但是父程式沒有讀取子程式狀態,子程式加入Z狀態
  • 系統呼叫exit,它的作用是使程式退出,但也僅僅限於將一個正常的程式變成一個殭屍程式,並不能將其完全銷燬

一個殭屍程式的例子

一個程式使用fork建立子程式,如果子程式退出,而父程式並沒有呼叫wait/waitpid獲取子程式的狀態資訊,那麼子程式的程式描述符仍然儲存在系統中,這種程式就稱之為殭屍程式

  1 #include<stdio.h>
  2 #include<errno.h>
  3 #include<stdlib.h>
  4 
  5 int main()
  6 {
  7     pid_t id = fork();
  8     if(id<0)
  9     {
 10         perror("fork");
 11         return 1;
 12     }
 13     else if(id>0){//father  
 14         printf("I an father\n");
 15         sleep(3);
 16         system("ps -o pid,ppid,state,tty,command");
 17         printf("father is exiting\n");
 18         }
 19     else{
 20             printf("I am child process ,I am exiting.\n");
 21             exit(0);
 22             }
 23     return 0;
 24 }

執行結果如下: 

 

我們可以看到,子程式27675使殭屍程式

殭屍程式的危害:

  • 程式的退出狀態必須被維持下去,因為他要告訴父程式,你交給我的任務,我辦的怎麼樣了,可父程式如果一直不讀取,那麼子程式就會一直處於Z狀態
  • 維護退出狀態本身就要用記憶體的資料維護,也屬於程式基本資訊,所以存在task_struct(PBC)中,換句話說,Z狀態一直不退出,PCB就一直要維護它
  • 如果一個父程式建立了很多子程式,就是不回收,就會造成記憶體資源的浪費。因為資料結構物件本身就要佔記憶體,如果數量過多就會造成記憶體洩漏

殭屍程式的避免:

  • 父程式可以通過wait和waitpid等待函式等待子程式結束,這會導致父程式掛起
  • 如果父程式很忙,那麼可以用signal函式為SIGCHLD安裝handler,因為子程式結束後,父程式會收到該訊號,可以在handler中呼叫wait回收
  • 如果父程式不關心子程式什麼時候結束,那麼可以用signal(SIGCHLD,SIG_IGN)通知核心,自己對子程式的結束不感興趣,那麼子程式結束後,核心會回收,並不在給父程式傳送訊號
  • 還有一些技巧,就是fork倆次,父程式fork一個子程式,然後繼續工作,子程式fork一個孫子程式後退出,那麼孫子程式被init接管,孫子程式結束後,被init回收,不過子程式的回收還是要自己做

孤兒程式:

  • 父程式退出,子程式就被稱之為“孤兒程式”
  • 孤兒程式被1號init程式領養,當然要有init程式回收

程式碼演示:

 1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 
  6 int main()
  7 {
  8     pid_t id = fork();
  9     if(id<0)
 10     {
 11         perror("fork");
 12         return 1;
 13     }
 14     else if(id==0)
 15     {
 16         //child
 17         printf("I am child .");
 18         printf("pid: %d\tppid:%d\n",getpid(),getppid());
 19         printf("I will sleep ten ceconds.\n");
 20         sleep(10);
 21         printf("pid: %d\tppid:%d\n",getpid(),getppid());
 22         printf("child process id exited.\n");
 23     }
 24     else//father
 25     {
 26         printf("I am father,pid:%d\n",getpid());
 27         sleep(3);
 28         printf("father process is exited.\n");
 29         exit(0);
 30     }
 31     return 0;
 32 }

執行結果:

孤兒程式是沒有父程式的程式,孤兒程式會被孤兒院收養(init程式)。每當出現一個孤兒程式的時候,核心就把孤兒程式的父程式設定為init,而init程式會迴圈的wait()它的已經退出的子程式。這樣,當一個孤兒程式生命週期結束使用者,init程式就會處理它的一切善後工作

 

相關文章