進程有下面5種正常終止方式:
(1)在main函數(shù)內(nèi)執(zhí)行return語句。這等效于調(diào)用exit。
(2)調(diào)用exit函數(shù)。此函數(shù)有ISO C定義,其操作包括調(diào)用各終止處理程序(終止處理程序在調(diào)用atexit函數(shù)時登記),然后關(guān)閉所有標(biāo)準(zhǔn)I/O流等。
(3)調(diào)用_exit或_Exit函數(shù)。ISO C定義_Exit,其目的是為進程提供一種無需運行終止處理程序或信號處理程序而終止的方法。對標(biāo)準(zhǔn)I/O流是否進行沖洗,這取決于實現(xiàn)。在UNIX系統(tǒng)中,_Exit和_exit是同義的,并不清洗標(biāo)準(zhǔn)I/O流。_exit函數(shù)由exit調(diào)用,它處理UNIX特定的細節(jié)。
在大多數(shù)UNIX系統(tǒng)實現(xiàn)中,exit(3)是標(biāo)準(zhǔn)C庫中的一個函數(shù),而_exit(2)則是一個系統(tǒng)調(diào)用。
(4)進程的最后一個線程在其啟動例程中執(zhí)行返回語句。但是,該線程的返回值不會用作進程的返回值。當(dāng)最后一個線程從其啟動例程返回時,該進程以終止?fàn)顟B(tài)0返回。
(5)進程的最后一個線程調(diào)用pthread_exit函數(shù)。在這種情況下,進程終止?fàn)顟B(tài)總是0,這與傳送給pthread_exit的參數(shù)無關(guān)。
三種異常終止方式如下:
(1)調(diào)用abort。它產(chǎn)生SIGABRT信號,這是下一種異常終止的特例。
(2)當(dāng)進程接收到某些信號時。信號可由進程自身(例如調(diào)用abort函數(shù))、其他進程或內(nèi)核產(chǎn)生。
(3)最后一個線程對“取消”(cancellation)請求作出響應(yīng)。按系統(tǒng)默認(rèn),“取消”以延遲方式發(fā)生:一個線程要求取消另一個線程,一段時間之后,目標(biāo)線程終止。
不管進程如何終止,最后都會執(zhí)行內(nèi)核中的同一段代碼。這段代碼為相應(yīng)進程關(guān)閉所有打開描述符,釋放它所使用的存儲器等。
對于上述任意一種終止情形,我們都希望終止進程能夠通知其父進程它是如何終止的。對于三個終止函數(shù)(exit、_exit和_Exit),實現(xiàn)這一點的方法是,將其退出狀態(tài)(exit status)作為參數(shù)傳遞給函數(shù)。在異常終止情況下,內(nèi)核(不是進程本身)產(chǎn)生一個指示其異常終止原因的終止?fàn)顟B(tài)(termination status)。在任意一種情況下,該終止進程的父進程都能用wait或waitpid函數(shù)取得其終止?fàn)顟B(tài)。
注意,這里使用了“退出狀態(tài)”(它是傳向exit或_exit的參數(shù),或main的返回值)和“終止?fàn)顟B(tài)”兩個術(shù)語,以表示有所區(qū)別。在最后調(diào)用_exit時,內(nèi)核將退出狀態(tài)轉(zhuǎn)換成終止?fàn)顟B(tài)(回憶圖7-1http://www.CUOXin.com/nufangrensheng/p/3507921.html)。如果子進程正常終止,父進程可以獲得子進程的退出狀態(tài)。
在說明fork函數(shù)時,顯而易見,子進程是在父進程調(diào)用fork后生成的。上面又說了子進程將其終止?fàn)顟B(tài)返回給父進程。但是如果父進程在子進程之前終止,則將如何呢?其回答是:對于父進程已經(jīng)終止的所有進程,它們的父進程都改變?yōu)閕nit進程。我們稱這些進程由init進程領(lǐng)養(yǎng)。其操作過程大致如下:在一個進程終止時,內(nèi)核逐個檢查所有活動進程,以判斷它是否是正要終止進程的子進程,如果是,則將該進程的父進程ID更改為1(init進程的ID)。這種處理方法保證了每個進程都有一個父進程。
另一個我們關(guān)心的情況是如果子進程在父進程之前終止,那么父進程又如何能在做相應(yīng)檢查時得到子進程的終止?fàn)顟B(tài)呢?對此問題的回答是:內(nèi)核為每個終止子進程保存了一定量的信息,所以當(dāng)終止進程的父進程調(diào)用wait或waitpid時,可以得到這些信息。這些信息至少包括進程ID、該進程的終止?fàn)顟B(tài)、以及該進程使用的CPU時間總量。內(nèi)核可以釋放終止進程所使用的所有存儲區(qū),關(guān)閉其所有打開文件。在UNIX術(shù)語中,一個已經(jīng)終止,但是其父進程尚未對其進行善后處理(使用wait獲取終止子進程的有關(guān)信息,釋放它仍占用的資源)的進程稱為僵死進程(zombie)(更多關(guān)于僵尸進程可參考:http://www.CUOXin.com/bettercoder/p/3501086.html)。ps(1)命令將僵死進程的狀態(tài)打印為Z。如果編寫一個長期運行的程序,它調(diào)用fork產(chǎn)生了很多子進程,那么除非父進程等待取得子進程的終止?fàn)顟B(tài),否則這些子進程終止后就會變成僵死進程。
最后一個要考慮的問題是:一個由init進程領(lǐng)養(yǎng)的進程終止時會發(fā)生什么?它會不會變成一個僵死進程?對此問題的回答是:“否”,因為init被編寫成無論何時只要有一個子進程終止,init就會調(diào)用wait函數(shù)取得其終止?fàn)顟B(tài)。這樣也就防止了在系統(tǒng)中有很多僵死進程。當(dāng)提及“一個init的子進程”時,這指的可能是init直接產(chǎn)生的進程,也可能是其父進程已終止,由init領(lǐng)養(yǎng)的進程。
本篇博文內(nèi)容摘自《UNIX環(huán)境高級編程》(第二版),僅作個人學(xué)習(xí)記錄所用。關(guān)于本書可參考:http://www.apuebook.com/。
新聞熱點
疑難解答