特殊程序
Linux系統中有兩種特殊程序:僵屍程序、孤兒程序;
僵屍程序:當程式調用exit()函數後,該程序并不是馬上就消失,
而是留下一個稱為僵屍程序的資料結構。僵屍程序是一種特殊的
程序,他幾乎放棄程序退出前占用的所有記憶體,既沒有可執行代
碼也不能被排程,隻在程序清單中留下一個位置,記載程序退出
狀态等資訊供父程序收集。若父程序中沒有回收子程序的代碼,
子程序會一直處于僵屍狀态。子程序退出後能釋放使用者區,但
不能釋放核心區的一些資料。
孤兒程序:父程序死了,子程序還或者,子程序就變成了孤兒程序。
此時,在較低的一些Linux版本,子程序會被init程序領養,但較高
的一些版本被一個特殊的程序領養;
特殊程序的危害
特殊程序不能再次運作。卻會占據一定的記憶體空間,當系統中的僵屍程序數量過多時,不僅會占據系統記憶體,還會占用程序id;是以使用wait()、waitpid()可以避免僵屍程序産生。
如果僵屍程序已經産生,通常解決僵屍程序的方法就是終止其父程序。這樣僵屍程序就會作為孤兒程序被init程序(現在的版本可能不是init程序領養,總之會有一個特殊的系統程序領養),這個特殊的程序會不斷調用wait()函數來擷取子程序的狀态,收集退出的子程序的狀态,并清理它占用的空間。最後,孤兒程序永遠不可能稱為僵屍程序;
wait()函數
傳回值:調用成功,傳回捕捉到的僵屍态子程序的id;調用失敗,傳回-1,errno被設定為ECHILD;
參數status:status是一個傳出參數,用于擷取子程序的退出狀态,如果不關心子程序的退出狀态可以傳入NULL;
調用wait()函數的程序會被挂起,進入阻塞狀态。直到子程序變成僵屍程序,wait()函數捕捉到子程序的退出狀态才會轉變到運作狀态,回收子程序的資源并傳回;若沒有變為僵屍态的子程序,wait()函數會讓程序一直阻塞。目前程序如果有多個子程序,隻要捕捉到一個變為僵屍态的子程序資訊,wait()函數就會傳回子程序id恢複執行狀态;
子程序的退出狀态被存放在exit()函數的status參數的低八位中。使用正常方法讀取比較麻煩,是以Linux定義了兩個宏,用于擷取程序退出狀态。
WIFEXITED(status);用于判斷子程序是否正常退出,如果是,傳回非零值,否則傳回零;
WEXITSTATUS(status);WIFEXITED()函數通常與WEXITSTATUS()函數搭配使用;若WIFEXITED()傳回非0(即正常退出),則可以使用WEXITSTATUS()提取子程序的傳回值;
WIFSIGNALED(status) 如果子程序因為一個未捕獲的信号而終止,它就傳回真;否則傳回假。
WTERMSIG(status) 如果WIFSIGNALED(status)為真,則可以用該宏獲得導緻子程序終止的信号代碼。
WIFSTOPPED(status) 如果目前子程序被暫停了,則傳回真;否則傳回假。
WSTOPSIG(status) 如果WIFSTOPPED(status)為真,則可以使用該宏獲得導緻子程序暫停的信号代碼。
waitpid()函數
pid>0時,隻等待pid與該參數相同的子程序,如果該子程序一直沒有退出,那麼父程序會一直阻塞;
pid=0時,會等待同一個程序組的子程序,若子程序加入了其他程序組,waitpid()不再關心它的狀态;
pid=-1時,waitpid()與wait()函數相同,将阻塞等待并回收一個子程序;
pid<-1時,會等待指定程序組的任何子程序,程序組的id等于pid的絕對值;
int options
參數options提供了一些另外的選項來控制waitpid()函數的行為。如果不想使用這些選項,則可以把這個參數設為0。
主要使用的有以下兩個選項:
WNOHANG 如果pid指定的子程序沒有結束,則waitpid()函數立即傳回0,而不是阻塞在這個函數上等待;如果結束了,則傳回該子程序的程序号;
WUNTRACED 如果子程序進入暫停狀态,則馬上傳回。
這些參數可以用“|”運算符連接配接起來使用。
如果waitpid()函數執行成功,則傳回子程序的程序号;如果有錯誤發生,則傳回-1,并且将失敗的原因存放在errno變量中。
失敗的原因主要有:沒有子程序(errno設定為ECHILD),調用被某個信号中斷(errno設定為EINTR)或選項參數無效(errno設定為EINVAL)
如果像這樣調用waitpid函數:waitpid(-1, status, 0),這此時waitpid()函數就完全退化成了wait()函數。