fork vfork exit _exit (转)
原文地址:http://hi.baidu.com/ikaruga11/blog/item/fb6d75725a8d8d148701b080.html
APUE上的一個例子:
example1 (forkt.c ):
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int glob = 5;
int main()
{
??????? int var=10;
??????? pid_t pid;
??????? printf("befork vfork\n");
??????? if((pid = fork()) < 0){
??????????????? printf("error\n");
??????????????? exit(1);
??????? }else if(pid == 0){
??????????????? glob++;
??????????????? var++;
??????????????? _exit(0);
??????? }
??????? printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
??????? exit(0);
}
執行
./forkt.c
./forkt.c > temp.out
將分別輸出什么呢?
為了找出為什么會輸出如上內容,以及fork vfork exit _exit的區別,于是改造上面的代碼
example2:(省略了其他同上相同的代碼)
??????? printf("befork vfork\n");
??????? if((pid = fork()) < 0){
??????????????? printf("error\n");
??????????????? exit(1);
??????? }else if(pid == 0){
??????????????? glob++;
??????????????? var++;
??????????????? exit(0);
??????? }
??????? printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
??????? _exit(0);
執行
./forkt.c
./forkt.c > temp.out
將分別輸出什么呢?
example3:(省略了其他同上相同的代碼)
??????? printf("befork vfork\n");
??????? if((pid = vfork()) < 0){
??????????????? printf("error\n");
??????????????? exit(1);
??????? }else if(pid == 0){
??????????????? glob++;
??????????????? var++;
??????????????? _exit(0);
??????? }
??????? printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
??????? exit(0);
執行
./forkt.c
./forkt.c > temp.out
將分別輸出什么呢?
example4:(省略了其他同上相同的代碼)
??????? printf("befork vfork\n");
??????? if((pid = vfork()) < 0){
??????????????? printf("error\n");
??????????????? exit(1);
??????? }else if(pid == 0){
??????????????? glob++;
??????????????? var++;
??????????????? exit(0);
??????? }
??????? printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
??????? _exit(0);
./forkt.c
./forkt.c > temp.out
將分別輸出什么呢?
先把幾個概念縷一縷:
?? fork: 子進程擁有父進程的數據段、堆和棧的副本,父進程和子進程共享正文段。但現在很多實現卻并不是將父進程的數據段、堆棧段進行完全拷貝,而是采用寫時復制(copy-on-write),內核將其標記為只讀,(典型的頁式虛存)只有父進程或子進程對這些區域進行修改時內核才真正將那一頁進行拷貝,從物理上分離開。
?? vfork:由于在vfork后經常是跟著一個exec執行一個新的程序不會在用到原來的地址空間,所以vfork的子進程在調用exec或exit之前是在父進程的空間里運行的,這樣對于頁式虛存效率很高。另外,vfork的子進程總是先與父進程執行,但是子進程不能依賴與父進程的執行否則產生死鎖。
exit(0):根據實現的不同而不同,一般是刷新I/O緩沖區,關閉所有I/O標準流(APUE上如是說,但是我在linux下驗證的結果應該是沒有關閉),一般現在的I/O庫函數在關閉I/O流方面不自找麻煩了。
_exit(0):不刷新I/O緩沖區
標準I/O庫:
標準I/O庫是帶緩存的,如果標準輸出是連接到終端設備,則它是行緩沖的,否則是全緩沖的。行緩沖在接收到一個換行符才進行刷新,而全緩沖在緩沖區滿或者程序在執行exit退出后在執行緩沖區刷新
好了 ,現在我們來看看上面的例子到底輸出什么東東了
example1:
執行:./forkt.c
交互方式執行,則是行緩沖, befork vfork后跟一個換行符\n,則刷新緩沖區輸出 befork vfork,然后fork一個子進程,父子進程分別運行在不同的存儲空間,子進程執行_exit()退出,不刷新緩沖區,父進程執行最后一個printf,但由于沒有遇到\n,所以并不立即輸出,在執行exit(0)后刷新緩沖區,此時輸出
pid =6724, glob = 5, var =10
執行:./forkt.c > temp.out
非交互方式,則是全緩沖,首先執行printf("befork vfork\n")此時并不輸出,而是緩存在緩沖區,然后fork一個子進程,父子進程分別運行在不同的存儲空間,拷貝一份父進程中緩沖區的befork vfork\n 到子進程,子進程執行_exit()退出,不刷新緩沖區,父進程執行最后一個printf,也緩存起來并不立即輸出,在執行exit(0)后刷新緩沖區,此時輸出全部輸出
cat > temp.out 輸出如下:
befork vfork
pid =6731, glob = 5, var =10
example2:
執行:./forkt.c
交互方式執行,則是行緩沖, befork vfork后跟一個換行符\n,則刷新緩沖區輸出 befork vfork,然后fork一個子進程,父子進程分別運行在不同的存儲空間,子進程執行exit()刷新緩沖區退出,父進程執行最后一個 printf,但由于沒有遇到\n,所以并不立即輸出,在執行_exit(0)后由于不刷新緩沖區而退出,所以最后一個printf內容并不輸出。所以
執行:./forkt.c
befork vfork
執行:./forkt.c > temp.out
非交互方式,則是全緩沖,首先執行printf("befork vfork\n")此時并不輸出,而是緩存在緩沖區,然后fork一個子進程,父子進程分別運行在不同的存儲空間,同時拷貝一份父進程中緩沖區的befork vfork\n 到子進程,子進程執行exit()刷新緩沖區退出,此時輸出befork vfork\n ,父進程執行最后一個printf,也緩存起來并不立即輸出,在執行_exit(0)后由于不刷新緩沖區而退出,因此輸出
cat > temp.out 輸出如下:
befork vfork
example3:
執行:./forkt.c
交互方式執行,則是行緩沖, befork vfork后跟一個換行符\n,則刷新緩沖區輸出 befork vfork,然后vfork一個子進程,父子進程運行在相同的存儲空間,子進程執行_exit()不刷新緩沖區退出,父進程執行最后一個 printf,但由于沒有遇到\n,所以并不立即輸出,在執行exit(0)后刷新緩沖區而退出,所以最后一個printf內容輸出。所以
執行:./forkt.c
befork vfork
pid =6802, glob = 6, var =11
執行:./forkt.c > temp.out
非交互方式,則是全緩沖,首先執行printf("befork vfork\n")此時并不輸出,而是緩存在緩沖區,然后vfork一個子進程,父子進程運行在相同的存儲空間,子進程執行_exit()不刷新緩沖區退出,父進程執行最后一個printf,也緩存起來并不立即輸出,在執行exit(0)刷新緩沖區而退出,因此輸出
cat > temp.out 輸出如下:
befork vfork
pid =6808, glob = 6, var =11
example4:
執行:./forkt.c
befork vfork
pid =6802, glob = 6, var =11
執行:./forkt.c > temp.out
cat > temp.out 輸出如下:
befork vfork
pid =6808, glob = 6, var =11
?
另外
簡單的說,exit函數將終止調用進程。在退出程序之前,所有文件關閉,緩沖輸出內容將刷新定義,并調用所有已刷新的“出口函數”(由atexit定義)。 _exit:該函數是由Posix定義的,不會運行exit handler和signal handler,在UNIX系統中不會flush標準I/O流。 簡單的說,_exit終止調用進程,但不關閉文件,不清除輸出緩存,也不調用出口函數。 共同: 不管進程是如何終止的,內核都會關閉進程打開的所有file descriptors,釋放進程使用的memory! note: 在由‘fork()’創建的子進程分支里,正常情況下使用‘exit()’是不正確的,這是 因為使用它會導致標準輸入輸出的緩沖區被清空兩次,而且臨時文件被出乎意料的刪除(譯者注:臨時文件由tmpfile函數創建在系統臨時目錄下,文件名由系統隨機生成)。 在C++程序中情況會更糟,因為靜態目標(static objects)的析構函數(destructors)可以被錯誤地執行。 還有一些特殊情況,比如守護程序,它們的父進程需要調用‘_exit()’而不是子進程;適用于絕大多數情況的基本規則是,‘exit()’在每一次進入‘main’函數后只調用一次。在由‘vfork()’創建的子進程分支里,‘exit()’的使用將更加危險,因為它將影響 父進程的狀態
轉載于:https://www.cnblogs.com/Myhsg/archive/2009/09/07/1562080.html
總結
以上是生活随笔為你收集整理的fork vfork exit _exit (转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET MVC V2 Previ
- 下一篇: 佛祖说出的爱情箴言