- 相關(guān)推薦
關(guān)于Linux系統(tǒng)命令中exit與exit的區(qū)別
注:exit()就是退出,傳入的參數(shù)是程序退出時(shí)的狀態(tài)碼,0表示正常退出,其他表示非正常退出,一般都用-1或者1,標(biāo)準(zhǔn)C里有EXIT_SUCCESS和EXIT_FAILURE兩個(gè)宏,用exit(EXIT_SUCCESS);可讀性比較好一點(diǎn)。
作為系統(tǒng)調(diào)用而言,_exit和exit是一對(duì)孿生兄弟,它們究竟相似到什么程度,我們可以從Linux的源碼中找到答案:
#define__NR__exit__NR_exit/*摘自文件include/asm-i386/unistd.h第334行*/
"__NR_"是在Linux的源碼中為每個(gè)系統(tǒng)調(diào)用加上的前綴,請(qǐng)注意第一個(gè)exit前有2條下劃線(xiàn),第二個(gè)exit前只有1條下劃線(xiàn)。 這時(shí)隨便一個(gè)懂得C語(yǔ)言并且頭腦清醒的人都會(huì)說(shuō),_exit和exit沒(méi)有任何區(qū)別,但我們還要講一下這兩者之間的區(qū)別,這種區(qū)別主要體現(xiàn)在它們?cè)诤瘮?shù)庫(kù)中的定義。_exit在Linux函數(shù)庫(kù)中的原型是:
#include
和exit比較一下,exit()函數(shù)定義在stdlib.h中,而_exit()定義在unistd.h中,從名字上看,stdlib.h似乎比unistd.h高級(jí)一點(diǎn),那么,它們之間到底有什么區(qū)別呢? _exit()函數(shù)的作用最為簡(jiǎn)單:直接使進(jìn)程停止運(yùn)行,清除其使用的內(nèi)存空間,并銷(xiāo)毀其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu);exit()函數(shù)則在這些基礎(chǔ)上作了一些包裝,在執(zhí)行退出之前加了若干道工序,也是因?yàn)檫@個(gè)原因,有些人認(rèn)為exit已經(jīng)不能算是純粹的系統(tǒng)調(diào)用。 exit()函數(shù)與_exit()函數(shù)最大的區(qū)別就在于exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查文件的打開(kāi)情況,把文件緩沖區(qū)中的內(nèi)容寫(xiě)回文件,就是"清理I/O緩沖"。
exit()在結(jié)束調(diào)用它的進(jìn)程之前,要進(jìn)行如下步驟:
1.調(diào)用atexit()注冊(cè)的函數(shù)(出口函數(shù));按ATEXIT注冊(cè)時(shí)相反的順序調(diào)用所有由它注冊(cè)的函數(shù),這使得我們可以指定在程序終止時(shí)執(zhí)行自己的清理動(dòng)作.例如,保存程序狀態(tài)信息于某個(gè)文件,解開(kāi)對(duì)共享數(shù)據(jù)庫(kù)上的鎖等.
2.cleanup();關(guān)閉所有打開(kāi)的流,這將導(dǎo)致寫(xiě)所有被緩沖的輸出,刪除用TMPFILE函數(shù)建立的所有臨時(shí)文件.
3.最后調(diào)用_exit()函數(shù)終止進(jìn)程。
_exit做3件事(man): 1,Anyopenfiledescriptorsbelongingtotheprocessareclosed 2,anychildrenoftheprocessareinheritedbyprocess1,init 3,theprocess‘sparentissentaSIGCHLDsignal
exit執(zhí)行完清理工作后就調(diào)用_exit來(lái)終止進(jìn)程。
此外,另外一種解釋?zhuān)?/p>
簡(jiǎn)單的說(shuō),exit函數(shù)將終止調(diào)用進(jìn)程。在退出程序之前,所有文件關(guān)閉,緩沖輸出內(nèi)容將刷新定義,并調(diào)用所有已刷新的“出口函數(shù)”(由atexit定義)。
_exit:該函數(shù)是由Posix定義的,不會(huì)運(yùn)行exithandler和signalhandler,在UNIX系統(tǒng)中不會(huì)flush標(biāo)準(zhǔn)I/O流。
簡(jiǎn)單的說(shuō),_exit終止調(diào)用進(jìn)程,但不關(guān)閉文件,不清除輸出緩存,也不調(diào)用出口函數(shù)。
共同:
不管進(jìn)程是如何終止的,內(nèi)核都會(huì)關(guān)閉進(jìn)程打開(kāi)的所有filedescriptors,釋放進(jìn)程使用的memory!
更詳細(xì)的介紹:
Callingexit() Theexit()functioncausesnormalprogramtermination.
Theexit()functionperformsthefollowingfunctions:
1.AllfunctionsregisteredbytheStandardCatexit()functionarecalledinthereverse orderofregistration.Ifanyofthesefunctionscallsexit(),theresultsarenotportable. 2.Allopenoutputstreamsareflushed(datawrittenout)andthestreamsareclosed.
3.Allfilescreatedbytmpfile()ared.
4.The_exit()functioniscalled. Calling_exit() The_exit()functionperformsoperatingsystem-specificprogramterminationfunctions. Theseinclude: 1.Allopenfiledescriptorsanddirectorystreamsareclosed.
2.Iftheparentprocessisexecutingawait()orwaitpid(),theparentwakesupand statusismadeavailable.
3.Iftheparentisnotexecutingawait()orwaitpid(),thestatusissavedforreturnto theparentonasubsequentwait()orwaitpid(). 4.ChildrenoftheterminatedprocessareassignedanewparentprocessID.Note:the terminationofaparentdoesnotdirectlyterminateitschildren. 5.IftheimplementationsupportstheSIGCHLDsignal,aSIGCHLDissenttotheparent. 6.Severaljobcontrolsignalsaresent.
為何在一個(gè)fork的子進(jìn)程分支中使用_exit函數(shù)而不使用exit函數(shù)? ‘exit()’與‘_exit()’有不少區(qū)別在使用‘fork()’,特別是‘vfork()’時(shí)變得很 突出。
‘exit()’與‘_exit()’的基本區(qū)別在于前一個(gè)調(diào)用實(shí)施與調(diào)用庫(kù)里用戶(hù)狀態(tài)結(jié)構(gòu)(user-modeconstructs)有關(guān)的清除工作(clean-up),而且調(diào)用用戶(hù)自定義的清除程序(自定義清除程序由atexit函數(shù)定義,可定義多次,并以倒序執(zhí)行),相對(duì)應(yīng),_exit函數(shù)只為進(jìn)程實(shí)施內(nèi)核清除工作。 在由‘fork()’創(chuàng)建的子進(jìn)程分支里,正常情況下使用‘exit()’是不正確的,這是因?yàn)槭褂盟鼤?huì)導(dǎo)致標(biāo)準(zhǔn)輸入輸出(stdio:StandardInputOutput)的緩沖區(qū)被清空兩次,而且臨時(shí)文件被出乎意料的刪除(臨時(shí)文件由tmpfile函數(shù)創(chuàng)建在系統(tǒng)臨時(shí)目錄下,文件名由系統(tǒng)隨機(jī)生成)。在C++程序中情況會(huì)更糟,因?yàn)殪o態(tài)目標(biāo)(staticobjects)的析構(gòu)函數(shù)(destructors)可以被錯(cuò)誤地執(zhí)行。(還有一些特殊情況,比如守護(hù)程序,它們的父進(jìn)程需要調(diào)用‘_exit()’而不是子進(jìn)程;適用于絕大多數(shù)情況的基本規(guī)則是,‘exit()’在每一次進(jìn)入‘main’函數(shù)后只調(diào)用一次。) 在由‘vfork()’創(chuàng)建的子進(jìn)程分支里,‘exit()’的使用將更加危險(xiǎn),因?yàn)樗鼘⒂绊懜高M(jìn)程的狀態(tài)。
#include
子進(jìn)程關(guān)閉的是自己的,雖然他們共享標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)等“打開(kāi)的文件”,子進(jìn)程exit時(shí),也不過(guò)是遞減一個(gè)引用計(jì)數(shù),不可能關(guān)閉父進(jìn)程的,所以父進(jìn)程還是有輸出的。
但在其它UNIX系統(tǒng)上,父進(jìn)程可能沒(méi)有輸出,原因是子進(jìn)程調(diào)用了exit,它刷新關(guān)閉了所有標(biāo)準(zhǔn)I/O流,這包括標(biāo)準(zhǔn)輸出。雖然這是由子進(jìn)程執(zhí)行的,但卻是在父進(jìn)程的地址空間中進(jìn)行的,所以所有受到影響的標(biāo)準(zhǔn)I/OFILE對(duì)象都是在父進(jìn)程中的。當(dāng)父進(jìn)程調(diào)用printf時(shí),標(biāo)準(zhǔn)輸出已被關(guān)閉了,于是printf返回-1。
在Linux的標(biāo)準(zhǔn)函數(shù)庫(kù)中,有一套稱(chēng)作"高級(jí)I/O"的函數(shù),我們熟知的printf()、fopen()、fread()、fwrite()都在此列,它們也被稱(chēng)作"緩沖I/O(bufferedI/O)",其特征是對(duì)應(yīng)每一個(gè)打開(kāi)的文件,在內(nèi)存中都有一片緩沖區(qū),每次讀文件時(shí),會(huì)多讀出若干條記錄,這樣下次讀文件時(shí)就可以直接從內(nèi)存的緩沖區(qū)中讀取,每次寫(xiě)文件的時(shí)候,也僅僅是寫(xiě)入內(nèi)存中的緩沖區(qū),等滿(mǎn)足了一定的條件(達(dá)到一定數(shù)量,或遇到特定字符,如換行符和文件結(jié)束符EOF),再將緩沖區(qū)中的內(nèi)容一次性寫(xiě)入文件,這樣就大大增加了文件讀寫(xiě)的速度,但也為我們編程帶來(lái)了一點(diǎn)點(diǎn)麻煩。如果有一些數(shù)據(jù),我們認(rèn)為已經(jīng)寫(xiě)入了文件,實(shí)際上因?yàn)闆](méi)有滿(mǎn)足特定的條件,它們還只是保存在緩沖區(qū)內(nèi),這時(shí)我們用_exit()函數(shù)直接將進(jìn)程關(guān)閉,緩沖區(qū)中的數(shù)據(jù)就會(huì)丟失,反之,如果想保證數(shù)據(jù)的完整性,就一定要使用exit()函數(shù)。
Exit的函數(shù)聲明在stdlib.h頭文件中。
_exit的函數(shù)聲明在unistd.h頭文件當(dāng)中。
下面的實(shí)例比較了這兩個(gè)函數(shù)的區(qū)別。printf函數(shù)就是使用緩沖I/O的方式,該函數(shù)在遇到“n”換行符時(shí)自動(dòng)的從緩沖區(qū)中將記錄讀出。實(shí)例就是利用這個(gè)性質(zhì)進(jìn)行比較的。
exit.c源碼
#include
輸出信息:
Usingexit...
Thisisthecontentinbuffer
#include
則只輸出:
Usingexit...
說(shuō)明:在一個(gè)進(jìn)程調(diào)用了exit之后,該進(jìn)程并不會(huì)馬上完全消失,而是留下一個(gè)稱(chēng)為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu)。僵尸進(jìn)程是一種非常特殊的進(jìn)程,它幾乎已經(jīng)放棄了所有的內(nèi)存空間,沒(méi)有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進(jìn)程列表中保留一個(gè)位置,記載該進(jìn)程的退出狀態(tài)等信息供其它進(jìn)程收集,除此之外,僵尸進(jìn)程不再占有任何內(nèi)存空間。
#include
intmain() { printf("%c",‘c‘); _exit(0); }
【Linux系統(tǒng)命令中exit與exit的區(qū)別】相關(guān)文章:
linux系統(tǒng)命令11-23
linux系統(tǒng)命令(經(jīng)典)01-25
Linux系統(tǒng)中smbclient命令的使用方法03-02
Linux系統(tǒng)命令及使用技巧03-19
Linux系統(tǒng)的基本命令講解03-31