天天看點

由vfork()結合exit()想到的若幹問題

問題來源

看coolshell的一篇文章,先看代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
    int var;
    var = ;
    if ((pid = vfork()) < ) {
    // if ((pid = fork()) < 0) {
        printf("vfork error");
        exit(-);

    } else if (pid == ) { /* 子程序 */
        var++;
        return ;
        //exit(0);
        //_Exit(0);
        //_exit(0);        
    }
    printf("pid=%d, glob=%d, var=%d\n", getpid(), glob, var);
    return ;
}
           

為啥在 vfork() 建立的子程序裡,調用return()整個程式就挂掉?

弄清兩個問題

  • fork() VS vfork()
  • what’s the difference betw ‘return()’ &&’exit()’

[注]我并不想造這種沒有意義的輪子,我隻想借助該問題複習完善自己的知識體系

fork() VS vfork()

  • fork()生成的子程序,子程序獲得父程序的資料空間,堆,棧的副本,但共享代碼段
  • vfork() 父子程序共享記憶體資料,fork()原來沒有引入寫時拷貝,是以會有vfork() 函數的引入

return() VS exit()

我想先介紹介紹這兩個表面上的一些差別

(這個網上好多,還是總結下:)

return exit _exit
編譯器的輔助,關鍵字 系統調用
結束函數,并且傳回,底層表現實際為彈棧 一旦調用,整個程序結束,系統可擷取結束的傳回值,具體調用後發生的過程如下圖(終止處理程式,标準i/o 清理程式) 一旦調用直接傳回核心

先看看一個C 程式是如何啟動和終止的

由vfork()結合exit()想到的若幹問題

一個程式在彙編層次上是如何運作的:

_start:
call _libc_init_first
call _init
call atexit
call main
cal _exit
           
  • 首先明白:一個程式被運作,核心調用exec() 将使用者程式加載到記憶體,一個C程式被編譯好後,編譯器會加入一些啟動曆程代碼,彙編代碼的入口點是:_start ,在_start 裡面調用main(), 是以C程式代碼的入口是可以修改的(在編譯得到的彙編代碼中修改就行)

函數調用return or exit 後發生了啥?

  • 程式要結束,函數如果調用return() , 實際就是一個将彈棧的過程,

    最後main() 函數調用return() 後,等價與調用了exit()

根據POXIS exit() 首先調用個終止處理程式(可以用atexit()注冊終止處理程式),關閉各種打開的檔案流,最後調用_exit() or _Exit() 傳回核心

【上面總結的是正常退出的情況】

回到這題,vfork() 建立的子程序,共享父程序的堆棧,堆棧被銷毀,是以父程序就直接挂掉