exit()和_exit()函數
進程就好比人一樣有其生命,我們通過fork()函數來建立一個進程,那麼我們又是如何來中止進程呢。
進程退出
1.在Linux中任何讓一個進程退出
進程退出表示進程即將結束。在Linux中進程退出分為了正常退出和異常退出兩種。
1>正常退出
a. 在main()函數中執行return 。
b.調用exit()函數
c.調用_exit()函數
2>異常退出
a.調用about函數
b.進程收到某個訊號,而該訊號使程式終止。
Tiger-John說明:
不管是那種退出方式,系統最終都會執行核心中的同一代碼。這段代碼用來關閉進程所用已開啟的檔案描述符,釋放它所佔用的記憶體和其他資源。
3>比較以上幾種退出方式的不同點
(1)exit和return 的區別:
a.exit是一個函數,有參數。exit執行完後把控制權交給系統
b.return是函數執行完後的返回。renturn執行完後把控制權交給調用函數。
(2)exit和abort的區別:
a.exit是正常終止進程
b.about是異常終止。
現在我們重點瞭解exit()和_exit()函數
2.exit()和_exit()的學習
1>exit和_exit函數都是用來終止進程的。
當程式執行到exit或_exit時,系統無條件的停止剩下所有操作,清除包括PCB在內的各種資料結構,並終止本進程的運行。
2>exit在標頭檔stdlib.h中聲明,而_exit()聲明在標頭檔unistd.h中聲明。exit中的參數exit_code為0代表進程正常終止,若為其他值表示程式執行過程中有錯誤發生。
3>exit()和_exit()的區別:
a._exit()執行後立即返回給核心,而exit()要先執行一些清除操作,然後將控制權交給核心。
b.調用_exit函數時,其會關閉進程所有的檔案描述符,清理記憶體以及其他一些核心清理函數,但不會重新整理流(stdin, stdout, stderr ...). exit函數是在_exit函數之上的一個封裝,其會調用_exit,並在調用之前先重新整理流。
Tiger-John說明:
exit()函數與_exit()函數最大區別就在於exit()函數在調用exit系統之前要檢查檔案的開啟情況,把檔案緩衝區的內容寫迴文件。由於Linux的標準函數庫中,有一種被稱作“緩衝I/O”的操作,其特徵就是對應每一個開啟的檔案,在記憶體中都有一片緩衝區。每次讀檔案時,會連續的讀出若干條記錄,這樣在下次讀檔案時就可以直接從記憶體的緩衝區讀取;同樣,每次寫檔案的時候也僅僅是寫入記憶體的緩衝區,等滿足了一定的條件(如達到了一定數量或遇到特定字元等),再將緩衝區中的內容一次性寫入檔案。這種技術大大增加了檔案讀寫的速度,但也給編程代來了一點兒麻煩。比如有一些資料,認為已經寫入了檔案,實際上因為沒有滿足特定的條件,它們還只是儲存在緩衝區內,這時用_exit()函數直接將進程關閉,緩衝區的資料就會丟失。因此,要想保證資料的完整性,就一定要使用exit()函數。
c . 通過一個函數執行個體來看看它們之間的區別:
函數執行個體1 : exit.c
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 printf("using exit----/n");
7 printf("This is the content in buffer/n");
8 exit(0);
9 }
函數經過調試後
think@ubuntu:~/work/process_thread/exit$ gcc exit.c -o exit
think@ubuntu:~/work/process_thread/exit$ ./exit
執行結果為:
using exit----
This is the content in buffer
函數執行個體2:_exit.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main(void)
5 {
6 printf("using _exit--/n");
7 printf("This is the content in buffer");
8 _exit(0);
9 }
函數經過調試後
think@ubuntu:~/work/process_thread/exit$ gcc _exit.c -o _exit
think@ubuntu:~/work/process_thread/exit$ ./_exit
執行結果為:
using _exit--
Tiger-John說明:
1.printf函數就是使用緩衝I/O的方式,該函數在遇到“/n”分行符號時自動的從緩衝區中將記錄讀出。所以exit()將緩衝區的資料寫完後才退出,而_exit()函數直接退出。
2.大家也可以把函數執行個體2中的printf("This is the content in buffer");改為printf("This is the content in buffer/n")(即在printf中最後加一個/n看運行結果是什麼,為什麼會產生這樣的結果呢?)
Tiger-John補充:
父子進程終止的先後順序不同會產生不同的結果。
1>父進程先於子進程終止:
此種情況就是我們前面所用的孤兒進程。當父進程先退出時,系統會讓init進程接管子進程。
2>子進程先於父進程終止,而父進程又沒有調用wait函數
此種情況子進程進入僵死狀態,並且會一直保持下去直到系統重啟。子進程處於僵死狀態時,核心只儲存進程的一些必要資訊以備父進程所需。此時子進程始終佔有著資源,同時也減少了系統可以建立的最大進程數。
什麼是僵死狀態呢?
一個已經終止、但是其父進程尚未對其進行善後處理(擷取終止子進程的有關資訊,釋放它仍佔有的資源)的進程被稱為僵死進程(zombie)。ps命令將僵死進程的狀態列印為Z
3>子進程先於父進程終止,而父進程調用了wait函數
此時父進程會等待子進程結束。