在 UNIX 里,除了程序 0(即 PID=0 的交換程序,Swapper Process)以外的所有程序都是由其他程序使用系統呼叫 fork 建立的,這裡呼叫 fork 建立新程序的程序即為父程序,而相對應的為其建立出的程序則為子程序,因而除了程序 0 以外的程序都只有一個父程序,但一個程序可以有多個子程序。
操作系統核心以程序識別符號(Process Identifier,即 PID)來識別程序。程序 0 是系統引導時建立的一個特殊程序,在其呼叫 fork 建立出一個子程序(即 PID=1 的程序 1,又稱 init)後,程序 0 就轉為交換程序(有時也被稱為空閑程序),而程序 1(init 程序)就是系統里其他所有程序的祖先。
 
一、殭屍程序
1、什麼是殭屍程序?
當一個子程序結束執行(一般是呼叫 exit、執行時發生致命錯誤或收到終止訊號所導致)時,子程序的退出狀態(返回值)會回報給操作系統,系統則以 SIGCHLD 訊號將子程序被結束的事件告知父程序,此時子程序的程序控制塊(PCB)仍駐留在內存中。一般來說,收到 SIGCHLD 後,父程序會使用 wait 系統呼叫以取得子程序的退出狀態,然後核心就可以從內存中釋放已結束的子程序的 PCB;而如若父程序沒有這麼做的話,子程序的 PCB 就會一直駐留在內存中,也即成為殭屍程序。
 
2、殭屍程序的危害
由於子程序的結束和父程序的執行是一個非同步過程, 即父程序永遠無法預測子程序 到底什麼時候結束. 那麼不會因為父程序太忙來不及 wait 子程序, 或者說不知道子程序什麼時候結束, 而丟失子程序結束時的狀態資訊呢? 不會. 因為 UNIX 提供了一種機制可以保證 只要父程序想知道子程序結束時的狀態資訊, 就可以得到. 這種機制就是: 在每個程序退出的時候, 核心釋放該程序所有的資源, 包括開啟的檔案, 佔用的內存等. 但是仍然為其保留一定的資訊 (包括程序號 the process ID, 退出狀態 the termination status of the process, 執行時間 the amount of CPU time taken by the process 等), 直到父程序通過 wait / waitpid 來取時才釋放. 但這樣就導致了問題, 如果你程序不呼叫 wait / waitpid 的話, 那麼保留的那段資訊就不會釋放, 其程序號就會一定被佔用, 但是系統所能使用的程序號是有限的, 如果大量的產生僵死程序, 將因為沒有可用的程序號而導致系統不能產生新的程序. 此即為殭屍程序的危害應當避免。
 
3、殭屍程序的清理
為避免產生殭屍程序,實際應用中一般採取的方式是:
1)將父程序中對 SIGCHLD 訊號的處理函式設為 SIG_IGN(忽略訊號);
2)fork 兩次並殺死一級子程序,令二級子程序成為孤兒程序而被 init 所 “收養”、清理。
 
二、 孤兒程序
1、什麼是孤兒程序?
孤兒程序則是指父程序結束後仍在執行的子程序。在類 UNIX 系統中,孤兒程序一般會被 init 程序所 “收養”,成為 init 的子程序。
 
2、孤兒程序的危害
孤兒程序是沒有父程序的程序,孤兒程序這個重任就落到了 init 程序身上,init 程序就好像是一個民政局,專門負責處理孤兒程序的善後工作。每當出現一個孤兒程序的時候,核心就把孤 兒程序的父程序設定為 init,而 init 程序會迴圈地 wait() 它的已經退出的子程序。這樣,當一個孤兒程序凄涼地結束了其生命周期的時候,init 程序就會代表黨和政府出面處理它的一切善後工作。因此孤兒程序並不會有什麼危害。
 
三、Linux 中的程序基本狀態:
1、執行 (R) 狀態:CPU 正在執行,即程序正在佔用 CPU。
2、就緒 (W) 狀態:程序已經具備的執行的一切條件,正在等待分配 CPU 的處理時間片。
3、停止 (S) 狀態:程序不能使用 CPU。
四、三個函式:
fork(); 功能: 建立一個新的程序。(fork()<0[出錯]、fork()==0[子程序]、fork()>0[父程序]
wait(); 功能:真正結束程序(收屍)。
exec(); 功能:執行外部程式。
孤兒程序與殭屍程序的區別:
殭屍程序會造成資源浪費,孤兒程序則不會!