Linux 進程的退出

目錄

進程退出

退出場景

常見的退出方法

正常退出

異常退出

_exit()系統調用

exit()函數

_exit()和exit()的區別

return 


進程退出

退出場景

  1. 正常符合預期退出
  2. 正常不符合預期退出
  3. 異常退出(執行過程中異常奔潰, 還未執行完)

常見的退出方法

正常退出

  1. main函數返回 ( return )
  2. 調用 exit( int status )函數
  3. 使用 _exit( int status )系統調用接口

可以使用ench $? 來查看進程退出碼

異常退出

  1. 向進程發送信號導致進程異常退出(如 Ctrl+c)
  2. 代碼錯誤導致進程運行時奔潰異常退出

說明 : 第二種情況是代碼錯誤導致異常終止沒什麼說的, 就是代碼問題

第一種情況是 Unix / Linux 系統中的信號是系統響應某些狀況而產生的事件,是進程間通信的一種方式。信號可以由一個進程發

送給另外進程,也可以由核發送給進程 .

信號處理程序

信號處理程序是進程在接收到信號後, 系統對信號的響應. 根據具體信號的涵義, 相應的默認信號處理程序會採取不同的信號處理方式:

  • 終止進程運行, 並且產生core dump (核心轉儲文件)(記錄一些錯誤信息, 方便用戶查看)
  • 終止進程運行
  • 忽略信號,進程繼續執行 .
  • 暫停進程運行 .
  • 如果進程已被暫停,重新調度進程繼續執行 .

前兩種方式會導致進程異常退出. 實際上,大多數默認信號處理程序都會終止進程的運行。

在進程接收到信號後,如果進程已經綁定自定義的信號處理程序, 進程會在用戶態執行自定義的信號處理程序. 如果沒有綁定,內

核會執行默認信號程序終止進程運行,  導致進程異常退出 .

例如: kill()函數, 在Shell中執行kill 指令, 在終端用鍵盤發送信號, 如:Ctrl+c , 都是發送信號來終止進程

_exit()系統調用

void _exit (int status)

頭文件 : unistd.h

參數 :status 定義了進程的終止狀態,父進程通過wait() 來獲取該值(wait() 函數, 用於進程等待, 下面說).

說明 :雖然status是int,佔但是僅有低8位可以被父進程所用. 在下面小結進程等待中詳細說

功能 :   直接使進程停止運行,清除其使用的內存空間,並銷燬其在內核中的各種數據結構

exit()函數

void exit (int status)

頭文件 : stdlib.h

參數status 與_exit中同理

exit() 底層封裝了 _exit 系統調用, 在底層調用_exit之前,  還做了下面的工作

  • 執行用戶通過 atexit 或 on_exit定義的清理函數。
  • 關閉所有打開的流,所有的緩存數據均被寫入 (即刷新緩衝區)
  • 調用 _exit()

_exit()和exit()的區別

  • 最大的區別是 exit()函數在調用 _exit() 系統調用之前要檢查文件的打開情況,把文件緩衝區中的內容寫回文件 (即刷新緩衝
    區), 然後將控制權交給內核 . _exit() 則是執行後立即返回給內核,而exit()要先執行一些清除操作,
     
  • 調用_exit函數時,會關閉進程所有的文件描述符,清理內存以及其他一些內核清理函數,但不會刷新緩衝區, exit函數是在_exit函數之上的一個封裝,其會調用_exit,並在調用之前先刷新緩衝區。
     
  • 補充: exit()函數在調用exit系統之前要檢查文件的打開情況,把文件緩衝區的內容寫回文件。由於Linux的標準函數庫中,由於內存中都有一片緩衝區.  每次讀文件時,會連續的讀出若干條記錄,這樣在下次讀文件時就可以直接從內存的緩衝區讀取.  同樣,每次寫文件的時候也僅僅是寫入內存的緩衝區,等滿足了一定的條件(如達到了一定數量或遇到特定字符等),再將緩衝區中的內容一次性寫入文件。這種技術大大增加了文件讀寫的速度,但也給編程代來了一點兒麻煩。比如有一些數據,認爲已經寫入了文件,實際上因爲沒有滿足特定的條件,它們還只是保存在緩衝區內,這時用_exit()函數直接將進程關閉,緩衝區的數據就會丟失。因此,要想保證數據的完整性,就一定要使用exit()函數。

舉栗子

#include<stdio.h>
#include<stdlib.h>
int main(){
    printf("hello world!");
    exit(0);
    return 0;
}

#include<stdio.h>
#include<unistd.h>
int main(){
    printf("hello world!");
    _exit(0);
}

可以看到, 並沒有輸出hello world! ,  這就_exit()沒有刷新緩衝區, 導致在緩衝區的字符串沒有打印到顯示器進程就退出了, 造成數據丟失 .(注意hello world! 後面不能有\n, 因爲\n會刷新輸出緩衝區,  影響結果) 

return 

return是一種更常見的退出進程方法. 執行return n等同於執行exit(n), 因爲main中 return n時, 系統會將main的返回值當做 exit()

的參數

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