問題來源
看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 程式是如何啟動和終止的

一個程式在彙編層次上是如何運作的:
_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() 建立的子程序,共享父程序的堆棧,堆棧被銷毀,是以父程序就直接挂掉