關於fork與vfork,exit與_exit

fork和vfork都是創建進程,exit和_exit都是退出進程,但之間也有些細微的區別,並且很讓人迷惑。一般情況下用fork創建的子進程用exit結束,而用vfork創建的進程則用_exit。那他們具體的區別在哪兒了,爲什麼這麼做!

預備知識:程序的存儲空間佈局,系統的緩衝區

 

c程序在內存中從高地址到低地址依次爲:

命令行參數和環境變量:存儲命令行的各個參數和系統的環境變量

棧段:局部變量(函數內部定義使用的變量)和函數調用存放的位置,此塊由操作系統處理

堆段:通常在堆裏面進行動態存儲分配,malloc就是分配堆裏面的空間,通常由程序員控制

數據段:存儲一些初始化數據和非初始化數據

正文段:cpu執行的機器碼

 

系統的緩衝區:

操作系統爲了提高文件都寫效率,都使用的緩存機制,當我們寫入一個文件時,很有可能寫入了緩衝區而沒有真真意義上的寫入硬盤,緩存分爲三個級別:

全緩衝:當緩衝空間(4096B或其它)寫滿後,一次性寫入硬盤,文件緩存通常如此

行緩衝:遇到輸入輸出遇到換行符,執行寫入操作,命令行界面就是使用行緩衝

無緩衝:這個就不用解釋了

 

fork與vfork

執行fork創建子進程時,子進程將拷貝父進程的數據段、堆段和棧段,此時父子進程的數據一致當互相獨立,各不影響,子進程對數據的處理不影響父進程。(其實當父子進程都不對三個段進行寫操作時,父子進程仍然共享數據段、堆段和棧段,當有任何一方有寫操作時,才產生副本,這種方式成爲寫是複製)

vfork與fork區別有兩點:1、vfork創建的子進程與父進程共享數據段,2、vfork創建的子進程優先於父進程執行,當子進程執行時,父進程進入阻塞狀態。

所以vfork產生的子進程對數據的修改一定可以影響到父進程的數據

 

exit與_exit

exit:當執行exit時,終止處理程序,執行標準的I/O清楚操作(將緩存中文件寫入),調用atexit,調用_exit。由此可見,exit是加強版的_exit.

_exit:通知內核,進程結束

 

測試exit和_exit

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <unistd.h> 
  4.  
  5. int main(void
  6.     printf("the first line\n"); 
  7.      
  8.     printf("the second line\n"); 
  9.      
  10.     exit(0); 

 

  1. eno@eno-ThinkPad-T420:~$ vim exit.c 
  2. eno@eno-ThinkPad-T420:~$ gcc exit.c -o exit 
  3. eno@eno-ThinkPad-T420:~$ ./exit  
  4. the first line 
  5. the second line 
  6. eno@eno-ThinkPad-T420:~$  

結果與預期相同,改爲_exit(0)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.  
  5. int main(void)  
  6. {    
  7.     printf("the first line\n");  
  8.  
  9.     printf("the second line\n");  
  10.  
  11.     _exit(0);  
  12. }  

 

  1. eno@eno-ThinkPad-T420:~$ ./_exit  
  2. the first line 
  3. the second line 
  4. eno@eno-ThinkPad-T420:~$  

結果怎麼還是一樣的,有的系統可能看到是沒有輸出,這都是正常的,每個系統最輸出的緩存機制可能不一致,通常爲行緩存,把他強制設置成全緩存看看:

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <unistd.h> 
  4.  
  5. int main(void
  6.     char buf[4096]; 
  7.   //設置成全緩存
  8.     setvbuf(stdout, buf, _IOFBF, 4096); 
  9.  
  10.     printf("the frist line\n"); 
  11.      
  12.     printf("the second line\n"); 
  13.      
  14.     _exit(0); 

ok,結果與預期相同,緩衝區的數據全部沒掉了

  1. eno@eno-ThinkPad-T420:~$ gcc _exit.c  -o _exit 
  2. eno@eno-ThinkPad-T420:~$ ./_exit  
  3. eno@eno-ThinkPad-T420:~$ 

這麼一比劃,就基本上明白了爲什麼fork產生的子進程要用exit而不用_exit了,如果緩衝區的東西都丟了,子進程所產生的數據就不完整,這對於程序使用者來說是不可接受的。那爲什麼vfork一般用_exit了,難道不怕丟數據麼?用vfork的子程序通常用_exit結束,而父進程通常用exit結束,這樣做數據就不會丟失,因爲他們共享一個數據段,父進程結束會處理所有打開的數據流,將其寫入。萬一子程序也用exit結束,那就比較麻煩了,試想一下父子進程都把同一份數據寫入,那個文件的價值有在哪裏。

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