記得之前初次接觸fork()函數的時候,一直被「printf」輸出多少次的問題弄得比較暈乎。不過,「黃天不負留心人"。哈~ 終於在學習進程和進程建立fork相關知識後,總算是大體摸清了其中的前因後果。廢話很少講,下面來談談本人的一點小小積累linux
1 /************************************************************************* 2 > File Name: 1.c 3 > Author: tp 4 > Mail: 5 > Created Time: Mon 07 May 2018 07:57:28 PM CST 6 ************************************************************************/ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <unistd.h> 11 int main( void) 12 { 13 printf("change world!\n"); 14 pid_t pid = fork(); 15 if( pid == -1) {perror("fork"),exit(1); } 16 17 printf( "pid=%d, returnVal=%d\n", getpid(), pid); 18 sleep( 1); 19 exit(0); 20 } ~
1 /************************************************************************* 2 > File Name: 2.c 3 > Author: tp 4 > Mail: 5 > Created Time: Mon 07 May 2018 12:40:39 PM CST 6 ************************************************************************/ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <unistd.h> 11 #include <fcntl.h> 12 13 int set = 110; 14 int main( void) 15 { 16 printf( "before fork\n"); 17 pid_t pid = fork( ); 18 if( pid < 0){ perror(" fork"),exit( 1);} 19 20 if( pid == 0) 21 { 22 ++set; 23 printf( "son pid=%d, %d\n", getpid(), set); 24 } 25 else 26 { 27 sleep( 1); 28 printf( "parent pid=%d , %d\n", getpid( ), set); 29 } 30 exit( 0); 31 }
看一下結果:算法
不難注意到 「before fork」這句話只是被打印了一次,這個從上面的例子,這不難理解;與此同時子進程中的set的值被改變了。此時再進行一個重定向操做會發生什麼網絡
![](http://static.javashuo.com/static/loading.gif)
出現很神奇的現象! 這個時候打印了出了兩次「before fork」,不只僅是如此,上述針對父進程的標準輸出執行重定向操做還致使了子進程也執行重定向操做。數據結構
透過現象看本質,來細細分析一下。針對打印兩次「before fork」,首先,先要知道標準IO庫是是帶緩衝的,而像printf這種直接輸出到標準輸出時,這個緩衝區是由換行符刷新的;而當執行了重定向操做,這裏就是將標準輸出重定向到文件,文件就不會當即去刷新緩衝區(全緩衝的方式);好,因爲在fork以前調用了一次printf,但fork以後,該行數據仍存留在緩衝區中,而後父進程數據空間被複制到子進程中,該行數據去也被複制了過去,這樣父子進程都各自帶有該行內容的緩衝區了,至關於子進程緩衝區添加了一行「before fork」,而後在每一個進程exit以後,每一個緩衝區的內容就被寫到了相應的文件中。函數
再一個就是,在重定向父進程的標準輸出時,子進程標準輸出也被重定向。這就源於父子進程會共享全部的打開文件。 由於fork的特性就是將父進程全部打開文件描述符複製到子進程中。當父進程的標準輸出被重定向,子進程本是寫到標準輸出的時候,此時天然也改寫到那個對應的地方;與此同時,在父進程等待子進程執行時,子進程被改寫到文件show.out中,而後又更新了與父進程共享的該文件的偏移量;那麼在子進程終止後,父進程也寫到show.out中,同時其輸出還會追加在子進程所寫數據以後,這也就解釋了上面爲何「before fork」會在一個文件中打印兩次。性能
在fork以後處理文件描述符通常又如下兩種狀況:學習
1.父進程等待子進程完成。此種狀況,父進程無需對其描述符做任何處理。當子進程終止後,它曾進行過讀,寫操做的任一共享描述符的文件偏移已發生改變。spa
2.父子進程各自執行不一樣的程序段。這樣fork以後,父進程和子進程各自關閉它們再也不使用的文件描述符,這樣就避免干擾對方使用的文件描述符了。這相似於網絡服務進程。.net
同時父子進程也是有區別的:它們不只僅是兩個返回值不一樣;它們各自的父進程也不一樣,父進程的父進程是ID不變的;還有子進程不繼承父進程設置的文件鎖,子進程未處理的信號集會設置爲空集等不一樣code
vfork和fork之間的區別: