linux中的exit

C標準定義了下面的退出函數:

    #include <stdlib.h>

    void exit(int status);

    void _Exit(int status);

    int atexit(void (*function)(void));

    函數功能介紹如下:

    void exit(int status)

    該函數終止調用的程序。status傳遞給系統用於父進程恢復。程序退出之前,exit()調用所有以atexit()註冊的函數,清空所有打開的<stdio.h> FILE*流的緩衝區並關閉流,然後刪除所有由tmpfile()創建的臨時文件。進程退出時,內核關閉所有剩下的已打開文件(即那些由open()creat()或文件描述符繼承打開的文件),釋放其地址空間,然後釋放所有其他使用的資源。exit()從不返回。

    void _Exit(int status)

該函數基本上與POSIX_exit()函數相同

    int atexit(void (*function)(void))

    function是一個函數指針,指向程序退出時候調用的一個回調函數。exit()在其關閉文件和終止之前調用該回調函數。這個想法在於程序能夠在最終關閉之前提供一個或者多個運行的清理函數。提供一個函數被成爲註冊該函數。

    atexit()成功時返回0,出錯時返回-1並設置相應的errno

    下面的程序沒有有用的功能,但它演示瞭如何使用atexit()

    void callback1(void){printf("callback called\n");}

    void callback2(void)(printf("callback called\n");}

    void callback3(void)(printf("callback called\n");}

    int main(int argc,char* argv[])

    {

         printf("registering callback1\n");atexit(callback1);

         printf("registering callback2\n");atexit(callback2);

         printf("registering callback3\n");atexit(callback3);

         printf("exiting now\n");

         exit(0);

    }

    下面是程序的運行結果:

    $atexit

    registering callback1

    registering callback2

    registering callback3

    exiting now

    callback3 called

    callback2 called

    callback1 called

    正如上例所示,使用atexit()註冊的函數運行時的順序和註冊的順序相反:最近註冊的最先運行(這也稱爲後進先出(last-in-first-out),縮寫爲LIFO)。

    POSIX定義了_exit()函數。與exit()不同,exit()調用回調函數並進行<stdio.h>清理,_exit()立即死亡的函數:

    #include <unistd.h>

    void _exit(int status);

    _exit終止調用進程,但不關閉文件,不清除輸出緩存,也不調用出口函數。exit函數將終止調用進程。在退出程序之前,所有文件關閉,緩衝輸出內容將刷新定義,並調用所有已刷新的出口函數(由atexit定義)。

    實際上,ISO C_Exit()函數與_exit()相同。C函數指出_Exit()是否調用以atexit()註冊的函數並關閉打開的文件取決與實現。對於GLIBC系統,可能不會,即_Exit()_exit()表現相似。

    使用_exit()的時機是在fork()產生的子進程中調用exec()失敗的時候。這種情況下,不需要使用通常的exit(),因爲它會清空所有由FILE*流保存的緩衝區數據。隨後父進程清空其緩衝區拷貝時,導致緩衝的數據被寫了兩次;顯然這不是很恰當。

    例如,加入你運行了一個shell命令,並且自己調用fork()exec()。代碼可能如下所示:

    char *shellcommand="...";

    pid_t child;

    if((child=fork())==0){

         execl("/bin/sh","sh","-c",shellcommand,NULL);

         _exit(errno==ENOENT?127:126);

    }

    errno測試和退出值採取了POSIX shell所使用的慣例。如果要求的程序沒有退出(ENOENT——目錄中沒有它的項),則退出值爲127。否則,文件同樣退出,但由於其他原因不能夠被exec()執行,則退出狀態爲126。在你自己的程序中採取這個慣例將會是個好主意。

    簡言之,爲了更好地使用exit()atexit(),你應該遵循一下規則:

    1、定義一個較小的退出狀態值的集合,你的程序使用該集合中的值與其調用者進行通信。在你的代碼中使用#define常量或enum定義這些值。

    2、決定是否有必要與atexit()一起使用回調函數。如果有必要,則在main()中適當地方註冊這些函數;例如,在解析選項之後以及初始化任何回調函數可能清除的數據結構之後,記住函數以LIFOlast-in-first-out)順序進行調用。

    3、如果出錯,在任一地方都可以使用exit()從程序退出,退出是能夠發生的正確行爲。同時使用你定義的錯誤代碼。

    4main()函數是個例外,你可以在其中使用return。我們自己的風格是,通常出問題時使用exit(),而如果一切正常,在main()結尾處使用“return 0”

    5、如果調用exec()失敗,則在子進程中使用_exit()_Exit()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章