atexit函數詳解(登記函數和終止處理函數)

查看原文

atexit函數詳解

對C語言有所瞭解的人都知道main函數是整個程序的入口,但是其實不然,在內核中可以使用鏈接器來設置程序的開始地方。當內核使⽤⼀個exec函數執⾏C程序時,在調⽤main函數之前先調⽤⼀個特殊的啓動例程,可執⾏程序將此例程指定爲程序的起始地址。啓動例程從內核獲取命令⾏參數和環境變量,然後爲調⽤main函數做好準備。
前面我們關注的是程序開始進入時的調用函數,而atexit函數是一個特殊的函數,它是在正常程序退出時調用的函數,我們把他叫爲登記函數

//函數原型
int atexit (void (*)(void))

⼀個進程可以登記若⼲個(具體⾃⼰驗證⼀下)個函數,這些函數由exit⾃動調⽤,這些函數被稱爲終⽌處理函數, atexit函數可以登記這些函數。 exit調⽤終⽌處理函數的順序和atexit登記的順序相反(網上很多說造成順序相反的原因是參數壓棧造成的,參數的壓棧是先進後出,和函數的棧幀相同),如果⼀個函數被多次登記,也會被多次調⽤。

atexit函數調用時機

以下函數的調用時程序異常或者正常終止:

進程終⽌的⽅式有8種,前5種爲正常終⽌,後三種爲異常終⽌:
1 從main函數返回;
2 調⽤exit函數;
3 調⽤_exit或_Exit;
4 最後⼀個線程從啓動例程返回;
5 最後⼀個線程調⽤pthread_exit;
6 調⽤abort函數;
7 接到⼀個信號並終⽌;
8 最後⼀個線程對取消請求做出響應。

exit()和_exit()以及_Exit()函數的本質區別是是否立即進入內核,_exit()以及_Exit()函數都是在調用後立即進入內核,而不會執行一些清理處理,但是exit()則會執行一些清理處理,這也是爲什麼會存在atexit()函數的原因,因爲exit()函數需要執行清理處理,需要執行一系列的操作,這些終止處理函數實際上就是完成各種所謂的清除操作的實際執行體。

下面我們來驗證atexit的調用順序和退出順序:

#include<stdio.h> 
#include<stdlib.h>  //atexit函數所屬頭文件
   
void func1() 
{ 
    printf("The process is done...\n"); 
} 
void func2() 
{ 
    printf("Clean up the processing\n"); 
} 
void func3() 
{ 
    printf("Exit sucessful..\n"); 
} 
int main() 
{ 
  //其作用是註冊某一個函數,當進程執行結束時,會自動調用註冊的函數
  //註冊幾次,就執行幾次
    atexit(func1); 
    atexit(func2); 
    atexit(func3); 
    exit(0); 
} 

運行截圖:
在這裏插入圖片描述
我們可以看到atexit函數的調用順序是和登記順序相反的。

atexit函數的用途也是比較廣泛的:可以按照你予設的順序摧毀全局變量(類),例如有個log類,你在其它的全局類裏也有可能調用到Log類寫日誌。所以log 類必須最後被析構 。假如沒有規定析構順序,那麼程序在退出時將有可能首先析構log類,那麼其它的全局類在此時將無法正確寫日誌。 把數據寫回文件, 刪除臨時文件, 這纔是真正有用的.

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