fork在面試中常常被問到,在這裏複習一下。面試
frok建立子進程,父子進程共享.text段,子進程得到父進程數據段、堆和棧的副本,因爲在fork以後常常跟隨者exec,因此不少實現並不執行父進程數據段、堆和棧的徹底複製,而是使用寫時複製(Copy-On-Write,COW)技術。這些區域由父子進程共享,並被內核設爲只讀,若是父子進程試圖修改這些區域,則內核只爲修改區域的那塊內存製做一個副本。函數
接下來的程序演示一下fork函數的功能spa
#include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<sys/types.h> void err_sys(const char *s) { printf("error:%s",s); exit(EXIT_FAILURE); } int glob = 6; char buf[] = "a write to stdout\n"; int main() { int var; pid_t pid; var = 88; if(write(STDOUT_FILENO,buf,sizeof(buf)-1) != sizeof(buf)-1) err_sys("write error"); printf("before fork\n"); if((pid = fork())<0) err_sys("fork error"); else if(pid == 0) { glob++; var++; } else sleep(2); printf("pid = %d,glob = %d,var = %d\n",getpid(),glob,var); exit(0); }
編譯獲得fork_sample,運行結果以下:.net
當直接執行fork_sample時,結果不出乎意料。在fork前先打印"before fork\n",fork以後父子進程分別打印。unix
可是當程序輸出重定向到temp文件時(即./fork_sample > temp的做用),讀取temp文件(即cat temp),咱們發現"before fork\n"被輸出了兩遍,這是爲何呢?code
這得從標準I/O庫的緩衝提及。blog
標準I/O庫提供了三種類型的緩衝:進程
(1) 全緩衝:填滿標準I/O緩衝區才實際進行I/O操做。內存
(2)行緩衝:在輸入和輸出中遇到換行符時,標準I/O庫執行I/O操做,當流涉及終端時,一般使用行緩衝。get
(3)不帶緩衝:標準出錯流stderr一般是不帶緩衝的。
上面說的緩衝指的是應用層的緩衝,在進行實際的I/O操做時,相關的系統調用(read和write)其實在內核也有緩衝區的。
當直接執行./fork_sample時,因爲標準輸出時行緩衝的,因此遇到換行符'\n'後緩衝區被沖洗。
當將程序輸出重定向到別的文件時,是標準輸出是全緩衝的,fork以前printf的數據仍在緩衝區中,在fork時該緩衝區也被複制到子進程中,所以咱們就會看到"before fork\n"輸出了兩次。