1. 程式人生 > >Linux——僵死程序和孤兒程序

Linux——僵死程序和孤兒程序

一:定義

         首先明白,在linux系統中,子程序是通過父程序建立的,子程序自身再建立新的程序。並且父程序和子程序是非同步執行的,即父程序永遠無法預測子程序何時結束,當然也就不知道何時去收集子程序的退出資訊了。

孤兒程序:在一個父程序退出後,剩餘的它的一個子程序或者多個子程序仍然在執行,並沒有退出,那麼這些子程序就                   會變成孤兒程序,這些孤兒程序將被init程序(程序號為1)所收養,並由init程序對它們完成狀態收集工作。

僵死程序:一個程序使用了fork語句建立子程序,當子程序退出後,而父程序並沒有能獲取到子程序的狀態資訊,那麼子程序的程序描述符仍然儲存在系統中。這種程序稱之為僵死程序。可以使用ps -e命令檢視程序,可以檢視到僵死的子程序(程序後有<defunct>字樣)

二:為什麼僵死程序不利於我們的程序處理呢?

       程序新生成時,必須先分配PCB結構,後才生成程序主體。一般在程序結束時先釋放主體,然後才會釋放PCB(程序控制塊,一個PCB大概1.7K),但是在僵死程序中,當程序的主體釋放,但是PCB結構依舊不釋放。那麼實際上你這個子程序中的有效資料只有4個位元組

,不釋放PCB 的同時,將在這個子程序中就使得剩下的記憶體空間既無法釋放也無法得到重新利用,所以會造成大量的記憶體浪費。

舉例生成一個僵死程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 

int main ()
{
        pid_t p = fork();//進行fork操作,建立子程序
	if (p == -1)	
          {		
              printf("ERROR\n");	
          }	
        else if (p == 0)	
          {		
               printf("Child pid is:%d\n",getpid());   //子程序           
          }
	else 	
           {		
              while (1)		
                {			
                   printf("Father pid is:%d\n",getpid());    //父程序		
                   sleep(1);		//睡眠一秒
                }	
           }
     exit(0);
}

 

編譯執行之後,會列印輸出一次子程序的pid,隨後一直是父程序列印自己的pid。  

三:如何處理僵死程序呢

方法一:wait/waitpid函式: Pid_t wait(int *reval)

        既然是父程序沒有收到子程序的退出資訊,那麼我們給它用一個來使得能收到就OK了。wait函式就是用來應對這種情況的,父程序在呼叫wait函式之後就可以將自己阻塞,由wait自動分析是否當前程序的某個子程序已經退出,如果讓它找到了這樣一個已經變成殭屍的子程序,wait就會收集這個子程序的資訊,並把它徹底銷燬後返回;如果沒有找到這樣一個子程序,wait就會一直阻塞在這裡,直到有一個出現為止。其中的引數reval用來儲存被收集程序退出時的一些狀態,它是一個指向int型別的指標。但如果我們對這個子程序是如何死掉的毫不在意,只想把這個殭屍程序消滅掉,我們就可以設定這個引數為NULL

例如:pid = wait(NULL

在原始碼中的父程序塊中也只需要新增 wait(NULL),再執行的時候就會發現僵死程序已經被處理掉。

 

但是這樣會出現一個問題:

在阻塞的過程中,父程序停止了自己的執行。在實際應用中我們不可能為了處理一個僵死程序而令父程序一直wait。並且一個wait函式只能處理一個僵死程序,作用十分有限。

那麼就是能不能子程序在退出的時候它自己發出一個訊號,來告訴父程序:我要退出了,你快點來處理我吧!

答案當然是可以的!

方法二:使用訊號

訊號是系統預先定義好的特定的事件,訊號可以被產生,也可以被接收,產生和接收的實體就是程序)

  只需要在父程序塊中加入一行程式碼:signal(SIGCHLD,SIG_IGN);

   將 SIGCHLD訊號的操作設為SIG_IGN     
   signal(SIGCHLD,SIG_IGN);

   就可以不產生僵死程序了。呼叫這個signal函式就定義了父程序對子程序結束後返回的SIGCHLD訊號的響應方式:忽略訊號的響應方式有:預設   忽略   自定義),這種方式可以保持非同步,即處理僵死程序的同時,父程序還可以繼續執行不受影響。