我們都知道通過fork()系統調用我們可以創建一個和當前進程印象一樣的新進程.我們通常將新進程稱為子進程,而當前進程稱為父進程.而子進程繼承了父進程的整個地址空間,其中包括了進程上下文,堆棧地址,內存信息進程控制塊(PCB)等.
1.父子進程
那么我們首先來先說說父進程和子進程之間的區別:
- 父進程設置了鎖,子進程不繼承
- 進程ID不同
- 子進程的未決告警被清除
- 子進程的未決信號集設置為空集
2.fork系統調用說明
通過man手冊我們可以輕松知道fork()包含的頭文件<sys/types.h>和<unistd.h>,功能就是創建一個子進程.函數原型:pid_t fork(void),pid_t是帶一個代表經常號pid的數據結構.如果創建成功一個子進程,對於父進程來說是返回子進程的ID.而對於子進程來說就是返回0.而返回-1代表創建子進程失敗.
#include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <errno.h> #include <signal.h> int main(void) { pid_t pid ; signal(SIGCHLD,SIG_IGN); printf("before fork pid:%d\n",getpid()); int abc = 10; pid = fork(); if(pid == -1) //錯誤返回 { perror("tile"); return -1; } if(pid > 0) //父進程空間 { abc++; printf("parent:pid:%d \n",getpid()); printf("abc:%d \n",abc); sleep(20); } else if(pid == 0){ //子進程空間 abc++; printf("child:%d,parent: %d\n",getpid(),getppid()); printf("abc:%d",abc); } printf("fork after...\n"); }before fork pid:27319parent:pid:27319
before fork pid:27319parent:pid:27319
abc:11
before fork pid:27319child:27320,parent: 27319
abc:11fork after...
3.fork()系統調用注意點:
通過以上程序我們可以知道:1)fork系統調用之后,父進程和子進程交替執行,並且它們處於不同空間中。
2)fork()函數的一次調用返回2次返回,這個有點抽象難理解,此時二個進程處於獨立的空間,它們各自執行者自己的東西,不產生沖突,所以返回2次一次pid ==0,一次pid大於0.而至於是先子進程還是父進程先執行,這沒有確切的規定,是隨機的.
3)將fork()返回值大於零設置為父進程,這是因為子進程獲得父進程的pid相對容易,而父進程獲子進程pid叫難,所以在在fork()系統調用中將子進程的pid字節有它自己返回給父進程.
4)forl()的子執行過程在fork()之后並不是從頭開始,因為在fork()之前,父進程已經為子進程搭建好了運行環境了.所以字節有效代碼處開始.理解了上面四點,相信我們應該對此系統調用一定有較深的了解.
4.vfork()系統調用:
那么講完了fork(),我們不妨和vfork()比較,並且學習終結一下vfork(.);vfork()在某些情況下,我們知道vfork()與fork()執行結果是一樣的,除了子進程會執行一次exec系統調用或者調用_exit(0)退出.函數原型:pid_t vfork vfork(void),具體返回值與其中fork()類似. 這個函數時是在沒有實現寫時賦值前提下,所以現在我們並不推薦使用vfork().
- 結論如下 1)vfork() 子進程與父進程共享數據段
2)vfork() 中是子進程先執行,父進程后執行.
通常我們都是與exec函數在一起,在主進程中替換進程印象.