Linux——僵死程序和孤兒程序
一:定義
首先明白,在linux系統中,子程序是通過父程序建立的,子程序自身再建立新的程序。並且父程序和子程序是非同步執行的,即父程序永遠無法預測子程序何時結束,當然也就不知道何時去收集子程序的退出資訊了。
孤兒程序:在一個父程序退出後,剩餘的它的一個子程序或者多個子程序仍然在執行,並沒有退出,那麼這些子程序就 會變成孤兒程序,這些孤兒程序將被init程序(程序號為1)所收養,並由init程序對它們完成狀態收集工作。
僵死程序:一個程序使用了fork語句建立子程序,當子程序退出後,而父程序並沒有能獲取到子程序的狀態資訊,那麼子程序的程序描述符仍然儲存在系統中。這種程序稱之為僵死程序。可以使用ps -e命令檢視程序,可以檢視到僵死的子程序(程序後有<defunct>字樣)
二:為什麼僵死程序不利於我們的程序處理呢?
程序新生成時,必須先分配PCB結構,後才生成程序主體。一般在程序結束時,先釋放主體,然後才會釋放PCB(程序控制塊,一個PCB大概1.7K),但是在僵死程序中,當程序的主體釋放,但是PCB結構依舊不釋放。那麼實際上你這個子程序中的有效資料只有4個位元組
舉例生成一個僵死程序:
#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訊號的響應方式:忽略(訊號的響應方式有:預設 忽略 自定義),這種方式可以保持非同步,即處理僵死程序的同時,父程序還可以繼續執行不受影響。