第七章 進程環境
各位觀衆,今天節目的主要內容有:
1、 當執行程序時,其main函數是如何被調用的?
2、 命令行參數是如何傳送給執行程序的?
3、 典型的存儲器而已是什麼樣式?
4、 如何分配另外的存儲空間?
5、 進程如何使用環境變量?
6、 各種不同進程終止方式
另外,本期特別報導:
longjmp和setjmp函數以及它們與棧的交互作用;進程的資源限制。
請看詳細報導:
1、 main函數
C程序總是從main函數開始執行,當內核執行C程序時,在調用main前先會調用一個特殊的啓動例程,啓動例程從內核取得命令行參數和環境變量值,然後爲按上述方式調用 main函數做好安排。
那麼一個程序啓動了,又是如何終止的呢,請看繼續報導:進程終止。
2、 進程終止
有8種方式可使進程終止,其中5種爲正常終止,它們是:
1. 從main返回
2. 調用exit
3. 調用_exit或_Exit
4. 最後一個線程從其啓動例程返回(第11.5期節目中,將會做詳細報導)
5. 最後一個線程調用pthread_exit(第11.5期節目中,將會做詳細報導)
異常有3種方式,它們是:
1. 調用abort(第10.17期節目中,將會做詳細報導)
2. 接到一個信號並終止(第10.2期節目中,將會做詳細報導)
3. 最後一個線程對取消請求做出響應(第11.5和12.7期節目中,將會做詳細報導)
上一節提到到的啓動例程會使main返回後立即調用exit函數,如果啓動例程以C代碼形式表示(事實上啓動例程是常常使用匯編語言編寫),那麼它調用main函數的形式就可能是如下:
exit(main(argc,argv));
下面來看一看exit函數相關資料:
前面已經看到,exit 和他兩個兄弟 _exit _Exit三種方式可以正常終止程序,那麼這三個兄弟區別在哪裏?請看下面:
_exit和_Exit立即進入內核,而exit則先執行一些清理處理(包括調用執行各終止處理程序,送親所以有標準I/O流等),然後進入內核,所以exit要稍微勤快點,乾的事稍微多一點。
exit對於標準I/O庫的清理關閉操作主要是通過爲所有打開流執行fclose函數,回憶5.5期節目中對fclose的介紹,這會造成所有緩衝的輸出數據都被沖洗。
這三個兄弟,工作時都會帶一個整型參數,這個參數將被用於標明程序的終止狀態,也就是說,參數是什麼值,那麼,程序的終止狀態就是什麼值,對將對於我們判斷一處程序問題出在哪裏將非常有用。但是如果進程終止時出現以下三種情況:
1. 調用exit函數時沒有帶終止態
2. main執行了一個無返回值的return語句
3. main沒有聲明返回類型爲整型
程序的終止態就是未定義的。
另外,若main返回類型是整型,且在執行到最後一條語句時返回或隱式返回,那麼該進程終止狀態將是0。main函數中,返回一整型什與該值調用exit是等價的,於是,在main函數中:
exit(0);
等價於
return(0);
2.1 atexit函數
進程結束前期我們還可以調用一些函數做一些處理,這些函數被稱爲終止處理程序( exit handler),一個進程最多可以登記32個函數,函數將由exit自動調用,登記是由 atexit完成。定義如下:
#include <stdlib.h>
int atexit(void (*func)(void));
需要說明的是,exit調用終止處理程序的順序與它們登記的時候順序相反,同一函數若被登記多次,則也會被多次調用。另,exit執行時,首選調用各終止程序,然後再調用fclose,如果程序調用了exec函數族中任一函數,則將清除所有已安裝的終止處理程序。
注意,內核使程序執行的唯一方法是調用一個exec函數,進程自願終止的唯一方法是顯式或隱式地(通過調用exit)調用_exit或_Exit。進程也可以非自願地由一個信號使其終止。
3、 命令行參數
當一個程序執行時,調用exec的進程可將命令行參數傳遞給新程序,例子可以參照 main(int argc,char *argv[]),不再過多討論,另外需要說明一點是argv[argc]是一個空指針。
4、 C程序存儲空間佈局
C程序典型存儲器安排如下圖:
說明:
正文段:由CPU執行的機器指令部份,通常是正文段可以共享的且通常是隻讀的,以防止程序由於意外而修改其自身指令。
初始化數據段:通常被稱爲數據段,包含了程序中需明確地賦初值的變量。
非初始化數據段:程序開始前,內核將此段中的數據初始化爲0或空指針。如以下聲明:long sum[100];將會被放於非初始化數據段。
堆與棧不再細說。
另外,未初始化數據段內容並不放在磁盤上的程序文件中,需要存放的只有正文段和初始化數據段。