進程控制開發(fā)之:Linux進程控制編程
3.exit()和_exit()
(1)exit()和_exit()函數(shù)說明。
exit()和_exit()函數(shù)都是用來終止進程的。當(dāng)程序執(zhí)行到exit()或_exit()時,進程會無條件地停止剩下的所有操作,清除包括PCB在內(nèi)的各種數(shù)據(jù)結(jié)構(gòu),并終止本進程的運行。但是,這兩個函數(shù)還是有區(qū)別的,這兩個函數(shù)的調(diào)用過程如圖7.4所示。
圖7.4exit和_exit函數(shù)流程圖
從圖中可以看出,_exit()函數(shù)的作用是:直接使進程停止運行,清除其使用的內(nèi)存空間,并清除其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu);exit()函數(shù)則在這些基礎(chǔ)上做了一些包裝,在執(zhí)行退出之前加了若干道工序。exit()函數(shù)與_exit()函數(shù)最大的區(qū)別就在于exit()函數(shù)在調(diào)用exit系統(tǒng)之前要檢查文件的打開情況,把文件緩沖區(qū)中的內(nèi)容寫回文件,就是圖中的“清理I/O緩沖”一項。
由于在Linux的標(biāo)準(zhǔn)函數(shù)庫中,有一種被稱作“緩沖I/O(bufferedI/O)”操作,其特征就是對應(yīng)每一個打開的文件,在內(nèi)存中都有一片緩沖區(qū)。每次讀文件時,會連續(xù)讀出若干條記錄,這樣在下次讀文件時就可以直接從內(nèi)存的緩沖區(qū)中讀取;同樣,每次寫文件的時候,也僅僅是寫入內(nèi)存中的緩沖區(qū),等滿足了一定的條件(如達到一定數(shù)量或遇到特定字符等),再將緩沖區(qū)中的內(nèi)容一次性寫入文件。
這種技術(shù)大大增加了文件讀寫的速度,但也為編程帶來了一些麻煩。比如有些數(shù)據(jù),認(rèn)為已經(jīng)被寫入文件中,實際上因為沒有滿足特定的條件,它們還只是被保存在緩沖區(qū)內(nèi),這時用_exit()函數(shù)直接將進程關(guān)閉,緩沖區(qū)中的數(shù)據(jù)就會丟失。因此,若想保證數(shù)據(jù)的完整性,就一定要使用exit()函數(shù)。
(2)exit()和_exit()函數(shù)語法。
表7.5列出了exit()和_exit()函數(shù)的語法規(guī)范。
表7.5 exit()和_exit()函數(shù)族語法
所需頭文件 | exit:#includestdlib.h> |
_exit:#includeunistd.h> | |
函數(shù)原型 | exit:voidexit(intstatus) |
_exit:void_exit(intstatus) | |
函數(shù)傳入值 | status是一個整型的參數(shù),可以利用這個參數(shù)傳遞進程結(jié)束時的狀態(tài)。一般來說,0表示正常結(jié)束;其他的數(shù)值表示出現(xiàn)了錯誤,進程非正常結(jié)束。 |
(3)exit()和_exit()使用實例。
這兩個示例比較了exit()和_exit()兩個函數(shù)的區(qū)別。由于printf()函數(shù)使用的是緩沖I/O方式,該函數(shù)在遇到“n”換行符時自動從緩沖區(qū)中將記錄讀出。示例中就是利用這個性質(zhì)來進行比較的。以下是示例1的代碼:
/*exit.c*/
#includestdio.h>
#includestdlib.h>
intmain()
{
printf(Usingexit...n);
printf(Thisisthecontentinbuffer);
exit(0);
}
$./exit
Usingexit...
Thisisthecontentinbuffer$
讀者從輸出的結(jié)果中可以看到,調(diào)用exit()函數(shù)時,緩沖區(qū)中的記錄也能正常輸出。
以下是示例2的代碼:
/*_exit.c*/
#includestdio.h>
#includeunistd.h>
intmain()
{
printf(Using_exit...n);
printf(Thisisthecontentinbuffer);/*加上回車符之后結(jié)果又如何*/
_exit(0);
}
$./_exit
Using_exit...
$
讀者從最后的結(jié)果中可以看到,調(diào)用_exit()函數(shù)無法輸出緩沖區(qū)中的記錄。
小知識 | 在一個進程調(diào)用了exit()之后,該進程并不會立刻完全消失,而是留下一個稱為僵尸進程(Zombie)的數(shù)據(jù)結(jié)構(gòu)。僵尸進程是一種非常特殊的進程,它已經(jīng)放棄了幾乎所有的內(nèi)存空間,沒有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態(tài)等信息供其他進程收集,除此之外,僵尸進程不再占有任何內(nèi)存空間。 |
4.wait()和waitpid()
(1)wait()和waitpid()函數(shù)說明。
wait()函數(shù)是用于使父進程(也就是調(diào)用wait()的進程)阻塞,直到一個子進程結(jié)束或者該進程接到了一個指定的信號為止。如果該父進程沒有子進程或者他的子進程已經(jīng)結(jié)束,則wait()就會立即返回。
waitpid()的作用和wait()一樣,但它并不一定要等待第一個終止的子進程,它還有若干選項,如可提供一個非阻塞版本的wait()功能,也能支持作業(yè)控制。實際上wait()函數(shù)只是waitpid()函數(shù)的一個特例,在Linux內(nèi)部實現(xiàn)wait()函數(shù)時直接調(diào)用的就是waitpid()函數(shù)。
(2)wait()和waitpid()函數(shù)格式說明。
表7.6列出了wait()函數(shù)的語法規(guī)范。
表7.6 wait()函數(shù)族語法
所需頭文件 | #includesys/types.h> |
函數(shù)原型 | pid_twait(int*status) |
函數(shù)傳入值 | 這里的status是一個整型指針,是該子進程退出時的狀態(tài) |
函數(shù)返回值 | 成功:已結(jié)束運行的子進程的進程號 |
表7.7列出了waitpid()函數(shù)的語法規(guī)范。
表7.7 waitpid()函數(shù)語法
所需頭文件 | #includesys/types.h> |
函數(shù)原型 | pid_twaitpid(pid_tpid,int*status,intoptions) |
續(xù)表
函數(shù)傳入值 | Pid | pid>0:只等待進程ID等于pid的子進程,不管已經(jīng)有其他子進程運行結(jié)束退出了,只要指定的子進程還沒有結(jié)束,waitpid()就會一直等下去 | ||
pid=-1:等待任何一個子進程退出,此時和wait()作用一樣 | ||||
pid=0:等待其組ID等于調(diào)用進程的組ID的任一子進程 | ||||
pid-1:等待其組ID等于pid的絕對值的任一子進程 | ||||
status | 同wait() | |||
options | WNOHANG:若由pid指定的子進程不立即可用,則waitpid()不阻塞,此時返回值為0 | |||
WUNTRACED:若實現(xiàn)某支持作業(yè)控制,則由pid指定的任一子進程狀態(tài)已暫停,且其狀態(tài)自暫停以來還未報告過,則返回其狀態(tài) | ||||
0:同wait(),阻塞父進程,等待子進程退出 | ||||
函數(shù)返回值 | 正常:已經(jīng)結(jié)束運行的子進程的進程號 | |||
使用選項WNOHANG且沒有子進程退出:0 | ||||
調(diào)用出錯:-1 |
評論