一、定義
1.fork系統調用用於創建一個新進程,稱為子進程,它與進程(稱為系統調用fork的進程)同時運行,此進程稱為父進程。創建新的子進程后,兩個進程將執行fork()系統調用之后的下一條指令。子進程使用相同的pc(程序計數器),相同的CPU寄存器,在父進程中使用的相同打開文件。
它不需要參數並返回一個整數值。下面是fork()返回的不同值。
負值:創建子進程失敗。
零:返回到新創建的子進程。
正值:返回父進程或調用者。該值包含新創建的子進程的進程ID。
2.所要用到的頭文件有:
#include<sys/types.h>
#include<unistd.h>
3.說明:
——父、子進程完全一樣(代碼、數據),子進程從fork內部開始執行,fork返回子進程的pid后,接着執行下一條語句。
——該函數被調用一次,但返回兩次。兩次返回的區別是子進程的返回值是0,而父進程的返回值則是子進程的ID。
——一般來說,在fork之后是父進程先執行還是子進程先執行是取決於內核鎖使用的調度算法。
4.示例代碼(一)——這段程序通過fork函數不同的返回值來驗證不同的進程在運行,同時通過一些全局變量和局部變量來看到父子進程之間的繼承關系。
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int galbol = 6;//定義全局變量 char buf[] = "Hello Linux";//定義一個字符串 int main(){ int var = 88;//定義一個局部變量 pid_t pid;//(pid_t 是一個宏定義,其實質是int 被定義在#include<sys/types.h>中) puts(buf);//輸出字符串 pid = fork();//執行fork函數並把返回值賦給pid if (pid < 0)//如果返回值小於0,則創建失敗 { printf("error\n"); exit(0); } if (pid == 0)//返回值等於0,表示創建成功,是子進程運行 { printf("This is children process!\n"); galbol++; var++; } else //如果返回ID就是父進程 { printf("This is parent process\n"); } printf("pid=%d,ppid=%d,galbol=%d,var=%d\n",getpid(),getppid(),galbol,var);//用來測試的變量 return 0; }
運行結果
講解一下運行結果,首先輸出了"Hello Linux!",這是我們放在創建進程之前的一個輸出,接着創建一個進程,返回值是ID,則表明當前是父進程,接着輸出幾個變量,當前進程ID和父進程ID,變量galbol和val,由於在父進程中沒有對兩個變量的值進行修改,所以兩個變量的值未發生改變。那接下來就是子進程,返回值是0,輸出自己是子進程,然后執行子進程的代碼,可以看到子進程的pid=5263,父進程ID=5983,剛好等於前面父進程的ID,並且修改了兩個變量的值。
5.示例代碼(二)——這次的demo是在父進程中打開一個文本文件,並進行讀操作,再看創建的子進程能否也讀取與父進程一樣的文本文件。
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> char str[10]; //定義一個數組,用來測試 int main() { FILE *fp; //fp文件指針 pid_t pid; //進程號 pid = fork(); fp = fopen("a.txt","r"); //以只讀的方式打開文件 if (fp == NULL) { printf("Open error!"); //如果指針返回的值為NULL,則打開失敗 exit(0); } else { if(pid < 0) //fork返回值小於0,創建失敗 { printf("Error!\n"); exit(0); } else if (pid == 0) //fork等於0,返回到新建的子進程 { fread(str,sizeof(char),2,fp); //讀兩個字符,並輸出到屏幕 puts(str); } else //否則返回到父進程 { sleep(2); fseek(fp,2L,SEEK_SET); //定位到子進程讀取的兩個字符之后開始 fread(str,sizeof(char),3,fp);//讀取三個字符 puts(str); } } return 0; }
這是a.txt里面的內容
這是運行結果
可以看到,子進程打開了與父進程一樣的文本文件。
6.總結一下:使用fork函數得到的子進程從父進程處繼承了整個進程的地址空間,包括進程上下文、進程堆棧、內存信息、打開的文件描述符、信號控制設置、進程優先級、進程組號、當前工作目錄、根目錄、資源限制、控制終端等