標籤:des style blog http color io os ar 使用
man vfork:
NAME
vfork - create a child process and block parent
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
DESCRIPTION
Standard description
(From POSIX.1) The vfork() function has the same effect as fork(2), except that the behav‐
ior is undefined if the process created by vfork() either modifies any data other than a
variable of type pid_t used to store the return value from vfork(), or returns from the
function in which vfork() was called, or calls any other function before successfully
calling _exit(2) or one of the exec(3) family of functions.
Linux description
vfork(), just like fork(2), creates a child process of the calling process. For details
and return value and errors, see fork(2).
vfork() is a special case of clone(2). It is used to create new processes without copying
the page tables of the parent process. It may be useful in performance-sensitive applica‐
tions where a child is created which then immediately issues an execve(2).
vfork() differs from fork(2) in that the calling thread is suspended until the child ter‐
minates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal
signal), or it makes a call to execve(2). Until that point, the child shares all memory
with its parent, including the stack. The child must not return from the current function
or call exit(3), but may call _exit(2).
As with fork(2), the child process created by vfork() inherits copies of various of the
caller‘s process attributes (e.g., file descriptors, signal dispositions, and current
working directory); the vfork() call differs only in the treatment of the virtual address
space, as described above.
Signals sent to the parent arrive after the child releases the parent‘s memory (i.e.,
after the child terminates or calls execve(2)).
建立一個新進程的方法只有由某個已存在的進程調用fork()或vfork(),當然某些進程如init等是作為系統啟動的一部風而被核心建立的。
一、fork
1. 調用方法
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
正確返回:在父進程中返回子進程的進程號,在子進程中返回0
錯誤返回:-1
子進程是父進程的一個拷貝。即,子進程從父進程得到了資料區段和堆棧段的拷貝,這些需要分配新的內存;而對於唯讀程式碼片段,通常使用共用記憶體的方式訪問。fork返回後,子進程和父進程都從調用fork函數返回處開始執行。
父進程與子進程的不同之處在於:fork的傳回值不同——父進程中的傳回值為子進程的進程號,而子進程為0
2. fork函數調用的用途
⑴ 一個進程希望複製自身,從而父子進程能同時執行不同段的代碼。
⑵ 進程想執行另外一個程式
二、vfork
1. 調用方法
與fork函數完全相同
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
正確返回:在父進程中返回子進程的進程號,在子進程中返回0
錯誤返回:-1
2. vfork函數調用的用途
用vfork建立的進程主要目的是用exec函數執行另外的程式,與fork的第二個用途相同
三、fork與vfork的區別
1. fork要拷貝父進程的資料區段;而vfork則不需要完全拷貝父進程的資料區段,在子進程沒有調用exec和exit之前,子進程與父進程共用資料區段
2. fork不對父子進程的執行次序進行任何限制;而在vfork調用中,子進程先運行,父進程掛起,直到子進程調用了exec或exit之後,父子進程的執行次序才不再有限制
四、結束子進程
結束子進程不用exit(0),而使用_exit(0)。這是因為_exit(0)在結束進程時,不對標準I/O流進行任何操作。而exit(0)則會關閉進程的所有標準I/O流。
由於子進程與父進程的運行是無關的,父進程可先於子進程運行,子進程也可先於父進程運行,所以下段程式可以有兩種運行結果。
#include<stdio.h>#include<sys/types.h>#include<unistd.h>int global=4;int main(){ pid_t pid; int vari=5; printf("before fork\n"); if((pid=fork())==0) { global++; vari--; printf("child changed\n"); } else printf("parent did nog changed\n"); printf("global=%d,vari=%d\n",global,vari); }
[email protected]:~/ms/linux/unp/unpMy/tcpcliserv# ./fork1
before fork
parent did nog changed
global=4,vari=5
[email protected]:~/ms/linux/unp/unpMy/tcpcliserv# child changed
global=5,vari=4
[email protected] src]# ./a.out
before fork
Child changed
globa = 5 vari = 4
Parent did not changde
globa = 4 vari = 5
vfork建立新進程的主要目的在於用exec函數執行另外的程式,實際上,在沒調用exec或exit之前子進程的運行中是與父進程共用資料區段的。在vfork調用中,子進程先運行,父進程掛起,直到子進程調用exec或exit,在這以後,父子進程的執行順序不再有限制。
#include<stdio.h>#include<sys/types.h>#include<unistd.h>int global=4;int main(){ pid_t pid; int vari=5; printf("before fork\n"); if((pid=vfork())==0) { global++; vari--; printf("child changed\n"); _exit(0); } else printf("parent did nog changed\n"); printf("global=%d,vari=%d\n",global,vari); exit(0); }
[email protected]:~/ms/linux/unp/unpMy/tcpcliserv# ./fork2
before fork
child changed
parent did nog changed
global=5,vari=4。
(從這裡可以看出共用了資料區段的。)
參考:http://blog.csdn.net/lingdxuyan/article/details/4996471
linux c 下exit(0);與_exit(0);的區別
#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(void){pid_t pid;if((pid=fork())==-1) { printf("error"); }else if(pid==0){printf("ok\n");exit(0);}else{printf("parent process,output begin\n");printf("hello word");_exit(0);}}
調試後你會發現沒有
hello word
exit是退出去先把記憶體中的資料輸出到檔案中,而_exit 這個直接退出,消除記憶體中的資料;
printf是標準行輸出,遇到“\n”或者是寫入的記憶體滿了才會標準輸出;
我們可以嘗試在hello word 中加入很多i,假設輸入2000個吧(關於行輸出自行google),再次調試發現,會有 hello 等字元,這就是溢出了。
回到前面,為什麼開始沒有hello,雖然hello word 在_exit前,但是你查看彙編會發現,他只是講資料存在記憶體中。沒有講資料真正輸出。當我們把_exit去掉 hello word就能顯示了。為什麼呢?這個就是編譯器自己加的了。
可以看出,_exit 函數的作用是:直接使進程停止運行,清除其使用的記憶體空間,並清除其在核心的各種資料結構;exit 函數則在這些基礎上做了一些小動作,在執行退出之前還加了若干道工序。exit() 函數與 _exit() 函數的最大區別在於exit()函數在調用exit 系統調用前要檢查檔案的開啟情況,把檔案緩衝區中的內容寫迴文件。也就是圖中的“清理I/O緩衝”。
所需標頭檔: exit: #include<stdlib.h>
_exit: #include<unistd.h>
函數原型:exit: void exit(int status)
_exit: void _exit(int status)
函數傳入值:status 是一個整型的參數,可以利用這個參數傳遞進程結束時的狀態。一般來說,0表示正常結束;其他的數值表示出現了錯誤,進程非正常結束。在實際編程時,父進程可以利用wait 系統調用接收子進程的傳回值,從而針對不同的情況進行不同的處理
參考:http://blog.csdn.net/lwj103862095/article/details/8640037
linux fork函數與vfork函數