複製進程映像:使用fork函數獲得的子進程從父進程繼承了整個進程的地址空間,包括:進程上下文、進程堆棧、內存信息、打開的文件描述符、信號控制設置、進程
優先級、進程組號當前工做目錄、根目錄、資源限制、控制終端等。
函數
子進程與父進程的區別在於:
1、父進程設置的鎖,子進程不繼承(例如對於一個排他鎖,父進程設置了鎖,子進程再設置,顯然不合適)
2、各自進程ID和父進程ID不一樣
3、子進程的未決警告被清除
4、子進程的未決信號集設置爲空集
#include <unistd.h>this
#include <sys/types.h>spa
pid_t fork(void);//無參數,失敗返回-1。兩次返回是在各自的地址空間中返回的。
A 進程fork進入內核
孤兒進程:父進程先於子進程退出,託孤給init進程
殭屍進程:子進程先退出,父進程還未查詢子進程的退出狀態,子進程就處於僵死狀態(defunct)。指針
爲什麼父進程返回值大於0(新進程ID號碼),子進程返回0:由於子進程PCB中保存有進程ID和父進程ID,全部即使返回0,子進程也能獲取這兩個值;但父進程若返回0,則它code
沒法得知新建立的子進程的ID。blog
fork一次調用兩次返回(是在各自的進程地址空間中返回的),fork成功,意味着建立了一個進程副本,兩個進程。fork陷入內核,拷貝父進程代碼,因此子進程也有fork,並返回。繼承
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<stdlib.h> 4 #include<stdio.h> 5 #include<errno.h> 6 #include<string.h> 7 #include<signal.h> 8 #define ERR_EXIT(m)\ 9 do\ 10 {\ 11 perror(m);\ 12 exit(EXIT_FAILURE);\ 13 }while(0) //宏要求一條語句 14 15 int main() 16 { 17 signal(SIGCHLD,SIG_IGN);//避免僵死進程 18 printf("before fork pid=%d\n",getpid()); 19 pid_t pid; 20 pid=fork();//進程代碼段、數據段、堆棧段等同樣,新進程的堆棧段和PCB也跟父進程同樣,因此下一條指令地址也同樣,因此不會從開頭運行。因此進程分支在fork以後。 21 if(pid==-1) 22 ERR_EXIT("fork error"); 23 if(pid>0) 24 { 25 printf("this is parent pid=%d, child pid=%d\n",getpid(),pid); 26 } 27 28 else if(pid==0) 29 { 30 //sleep(5);//父進程先結束 31 printf("this is child pid=%d, parent pid=%d\n",getpid(),getppid()); 32 } 33 34 return 0; 35 } 36 /* 37 子進程先結束 38 before fork pid=48714 39 this is parent pid=48714, child pid=48715 40 this is child pid=48715, parent pid=48714 41 */
fork函數陷阱:1-->2-->4-->8 (核心:fork開始,會有兩個進程執行相同代碼段)進程
#include<unistd.h> #include<sys/types.h> #include<stdlib.h> #include<stdio.h> #include<errno.h> #define ERR_EXIT(m)\ do\ {\ perror(m);\ exit(EXIT_FAILURE);\ }while(0) //宏要求一條語句 int main() { fork(); fork(); fork(); printf("ok\n"); return 0; /*8 ok ok ok ok ok ok ok ok */ }
寫時複製(copy on write):內存
若是多個進程要讀取(僅僅讀取)它們本身的那部分資源的副本,那麼複製是沒必要要的(好比代碼段),每一個進程只要保存一個指向這個資源的指針就能夠了。若是一個進程要修改本身那份資源的副本,那麼就會複製那份資源。這就是寫時複製。資源須要修改纔要複製。其餘進程仍然共享。實際上不會被修改的數據是共享的。資源