Linux系統調用:進程的終止


之前總結了Linux的系統創建,主要是fork()函數和vfork()函數,最近總結了Linux進程的終止,主要的調用是_exit()和exit().

先看看兩個函數的原型以及各自屬於的頭文件,可以發現這兩個方法的區別

_exit()函數:

    #include <unistd.h>  
      
    void _exit(int status);  

從_exit()的頭文件能夠發現,_exit()是屬於Linux的系統調用, 只能在Linux或者是Unix上才支持這個調用。

其中,status定了進程的終止狀態,其父進程可以通過wait()函數來獲取這個狀態,從而進行之后的執行操作。當status為0時,表示進程正常退出,反之則是非正常退出。調用_exit()會使進程總是成功終止,也就是說_exit()方法從不會返回。

此處需要注意的是,雖然status定義成了整型,但實際上只有低8位可用,其原因就是當以信號(signal)終止一個進程的時候,shell會將變量$?置為128與信號之和,以表征這一事實。如果這與進程調用_exit()時所使用相同status值混雜起來,將令shell無法分辨。(這個地方不是很理解)

exit()函數:

#include <stdlib.h>  
  
void exit(int status); 

從exit()的頭文件可以看出,exit()是C語言的庫函數,所以所有的C語言都支持這個方法。

exit()在調用的時候要做得工作會比較多,主要有如下幾個操作:

  1. 調用退出處理程序(通過atexit()和on_exit()注冊的函數),並且在有多個退出處理程序時,執行順序與注冊順序相反。
  2. 刷新stdio流緩沖區;
  3. 使用有status提供的值執行_exit()函數

我們通常在寫程序的時候,在main()函數結尾只是用了return n;來結尾,在這個地方,return n; 就相當於exit(n),在結束的時候主函數會將返回值作為調用exit()函數的參數。這個地方本人有個疑問,在exit()函數調用_exit()時,其參數使用前面的n,而在_exit(int status)中,status為0表示程序正常結束,如果在return的時候,指定的n不為0,是一個其他的數,Linux內部會怎么處理呢?

其實在進程終止的時候,還有一些更細致的操作,由於本人目前能力有限,先不做討論。


剛剛在前面提到了退出處理程序,現在來看看退出處理程序。

使用退出處理程序的原因就是,我們調用的exit()是C語言的庫函數,而庫函數對於進程的退出並沒有實際控制的權利,所以無法在進程退出時調用系統特定的清理函數,所以退出處理函數就應運而生。

GUNC 提供了一下兩種方式來注冊退出處理函數:

    #include <stdlib.h>  
      
    int atexit(void (*func)(void));  
      
    //退出處理函數的定義  
      
    void func(void) {  
        /* performance */  
    }  

需要注意的是:

  1. atexit()函數在出錯的時候返回的是非0值,不僅僅是負值;
  2. 同時,在退出處理函數中如果訪問了此前mian()函數中本地變量,那么main()函數的返回會導致未定義的行為;
  3. 當有多個退出處理程序的時候,退出處理程序的調用順序與之策順序是相反的,這一點的邏輯是,先注冊的通常是更為基本的清理動作,可能需要在后續注冊的函數后再執行;
  4. 一旦退出處理程序在無法返回——調用了_exit()或者因為信號而終止,其后的處理程序將不再執行。

以上的atexit()有兩個局限,第一是退出處理程序不能獲取當前進程退出時的狀態,而根據進程退出狀態來做相應的操作可以是支持的;第二就是不能給退出處理程序傳遞參數。

所以glibc提供了一個非標准的替代方法:on_exit()。其定義如下:

    #define _BSD_SOURCE  
    #include <stdlib.h>  
      
    int on_exit(void (*func)(int, void *),void *arg);  
      
    //退出處理函數定義  
    void func(int status, void *arg) {  
        /* Performace */  
    }  

和atexit()函數類似,on_exit()的出錯時返回值為非0。而on_exit()還不是所有標准都支持,還是應該盡量避免。

atexit()和on_exit()注冊的函數屬於同一個函數列表,在執行時與注冊的順序相反。

最后給一個例子僅供大家參考:

#define _BSD_SOURCE  
#include <stdlib.h>  
#include <sys/types.h>  
#include <stdio.h>  
  
static void atexitFunc1(void) {  
    printf("atexit function 1 called\n");  
}  
  
static void atexitFunc2(void) {  
    printf("atexit function 2 called\n");  
}  
  
static void onexitFunc(int exitStatus, void *arg) {  
    printf("on_exit function called: status=%d, arg=%ld\n",exitStatus, (long) arg);  
}  
  
int main(int argc, char *argv[]) {  
    if(on_exit(onexitFunc, (void *) 10) != 0)  
        perror("on_exit 1");  
    if(atexit(atexitFunc1) != 0)  
        perror("atexit 1");  
    if(atexit(atexitFunc2) != 0)  
        perror("atexit 2");  
    if(on_exit(onexitFunc, (void *) 10) != 0)  
        perror("on_exit 2");  
    exit(2);  
} 

執行的結果如下:

    on_exit function called: status=2, arg=20  
    atexit function 2 called  
    atexit function 1 called  
    on_exit function called: status=2, arg=10  

希望和大家多交流


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM