ateixt、ptread_exit 、exit和_exit、_Exit引發的思考和總結
編寫背後:視訊採集應用程式的main函式中atexit(&free_dev)的呼叫
基礎理解:
函式名: atexit
標頭檔案:#include<stdlib.h>
功 能: 註冊終止函式(即main執行結束後呼叫的函式)
用 法: int atexit(void (*func)(void));
注意:按照ISO C的規定,一個程序可以登記多達32個函式,這些函式將由exit自動呼叫。atexit()註冊的函式型別應為不接受任何引數的void函式,exit呼叫這些註冊函式的順序與它們登記時候的順序相反。同一個函式如若登記多次,則也會被呼叫多次。
程式例:
#include <stdio.h>
#include <stdlib.h>
void exit_fn1(void)
{
printf("Exit function #1 called\n");
}
void exit_fn2(void)
{
printf("Exit function #2 called\n");
}
int main(void)
{
/* post exit function #1 */
atexit(exit_fn1);
/* post exit function #2 */
atexit(exit_fn2);
return 0;
}
輸出:
Exit function #2 called
Exit function #1 called
程序的終止方式:
有8種方式使程序終止,其中前5種為正常終止,它們是
1:從 main 返回
2:呼叫 exit
3:呼叫 _exit 或 _Exit
4:最後一個執行緒從其啟動例程返回
5:最後一個執行緒呼叫 pthread_exit
異常終止有3種,它們是
6:呼叫 abort
7:接到一個訊號並終止
8:最後一個執行緒對取消請求做出響應
#include <stdlib.h?
void exit (int status);
void _Exit (int status);
#include <unistd.h>
void _exit (status);
其中呼叫 _exit,_Exit 都不會呼叫終止程式
異常終止也不會。
對比+例程---加深理解
對比atexit 、 exit、 _exit、 ptread_exit
關於atexit()函式:
main 函式執行完後,如果需要再執行一段程式碼的話可以呼叫atexit()註冊一個函式:例如:
#include<stdio.h>
#include<stdlib.h>
void fumc1()
{printf("next\n");}
void fumc2()
{printf("executed");}
void fumc3()
{printf("is");}
void fumc4()
{printf("this");}
void main()
{
char str[]="0123456789";
atexit(fumc1);
atexit(fumc2);
atexit(fumc3);
atexit(fumc4);
printf("%d\n",sizeof(str));
printf("main execued to the end. \n");
}
執行結果:
main execued to the end.
11
thisisexecutednext
本來到該結束程式printf("main execued to the end. \n");
但是還列印thisisexecutednext
說明:mian程式結束後,還執行atexit函式
關於exit、 _exit、 ptread_exit的區分:
(1)終止”程序” 呼叫:exit和_exit
注意:如果程序中任何一個執行緒中呼叫exit或_exit,那麼整個程序都會終止。(會導致執行緒退出)
(2)終止“執行緒”呼叫:ptread_exit
而“執行緒”的正常退出方式3種:
A執行緒從啟動例程中返回(return())
B執行緒可以被另一個程序終止
C執行緒自己呼叫pthread_exit函式
關於exit、 _exit 的區分
_exit()函式:的作用最為簡單:直接使程序停止執行,清除其使用的記憶體空間,並銷燬其在核心中的各種資料結構;
exit() 函式:則在這些基礎上作了一些包裝,在執行退出之前加了若干道工序,也是因為這個原因,有些人認為exit已經不能算是純粹的系統呼叫。
exit()函式與_exit()函式最大的區別就在於exit()函式在呼叫exit系統呼叫之前要檢查檔案的開啟情況,把檔案緩衝區中的內容寫回檔案,就是"清理I/O緩衝"。
在Linux的標準函式庫中,有一套稱作"高階I/O"的函式,我們熟知的printf()、fopen()、fread()、fwrite()都在此 列,它們也被稱作"緩衝I/O(buffered I/O)",其特徵是對應每一個開啟的檔案,在記憶體中都有一片緩衝區,每次讀檔案時,會多讀出若干條記錄,這樣下次讀檔案時就可以直接從記憶體的緩衝區中讀取,每次寫檔案的時候,也僅僅是寫入記憶體中的緩衝區,等滿足了一定的條件(達到一定數量,或遇到特定字元,如換行符和檔案結束符EOF),再將緩衝區中的
內容一次性寫入檔案,這樣就大大增加了檔案讀寫的速度,但也為我們程式設計帶來了一點點麻煩。如果有一些資料,我們認為已經寫入了檔案,實際上因為沒有滿足特定的條件,它們還只是儲存在緩衝區內,這時我們用_exit()函式直接將程序關閉,緩衝區中的資料就會丟失,反之,如果想保證資料的完整性,就一定要使用exit()函式。
下面我們來看兩小段程式並對比起輸出結果:
程式一:
#i nclude<stdlib.h>
main()
{
printf(" if i will be output ?");
printf(" if i will be in the buffer?");
exit(0);
}
輸出結果:
if i will be output ?if i will be in the buffer?
(如圖:為編譯和執行結果)
程式二:
#include<unistd.h>
main()
{
printf(" if i will be output ?");
printf(" if i will be in the buffer?");
_exit(0);
}
輸出結果:
(沒有任何輸出)
對比上面兩個結果,我們可以更好的理解上面提到過的這兩句關鍵的文字
1.exit()函式與_exit()函式最大的區別就在於exit()函式在呼叫exit系統呼叫之前要檢查檔案的開啟情況,把檔案緩衝區中的內容寫回檔案,就是"清理I/O緩衝"。
2.有一些資料,我們認為已經寫入了檔案,實際上因為沒有滿足特定的條件,它們還只是儲存在緩衝區內,這時我們用_exit()函式直接將程序關閉,緩衝區中的資料就會丟失,反之,如果想保證資料的完整性,就一定要使用exit()函式。
附:如果讀者對緩衝機制不太理解可以參見我部落格裡的另一篇博文《UNIX裡關於標準IO的幾種緩衝機制》,它可以幫助你更好的理解本文中關於exit和_exit()的區別。