先來看以下一段代碼(test.c):
1 #include<stdio.h> 2 #include<sys/types.h> 3 4 int main() 5 { 6 pid_t pid; 7 fprintf(stdout,"%s","Start fork..."); 8 pid = fork(); 9 switch(pid) 10 { 11 case -1: 12 break; 13 case 0: 14 printf("%s","Child process.\n"); 15 break; 16 default: 17 printf("%s","Parent process.\n"); 18 break; 19 } 20 return 0; 21 }
|
編譯執(zhí)行:
$gcc -o test test.c
$./test
Start fork...Child process.
Start fork...Parent process.
出乎意料的是,為什么"Start fork..."輸出了兩次呢?子進程是從fork之后的語句開始執(zhí)行的,那么多出來那個"Start fork..."是哪里來的呢?
先了解一下緩沖區(qū):
這個緩沖區(qū)既不是內核中的緩沖區(qū),也不是用戶分配的緩沖區(qū),而是有編譯器維護的用戶進程空間中的緩沖區(qū).緩沖區(qū)類型有:全緩沖(大部分緩沖都是這類型)、行緩沖、無緩沖。
標準里沒有規(guī)定各種流是什么緩沖,stderr和stdout是哪種緩沖類型是和環(huán)境相關的。 stderr 可能是無緩沖、行緩沖,但不能是全緩沖。stdin 和 stdout 可能是無緩沖、行緩沖,也可能是全緩沖。不過,stdin 和 stdout 如果分別是指鍵盤和顯示器等交互設備(interactive device)的話,那么只能是無緩沖或行緩沖。
默認情況下,printf()在屏幕輸出的時候是行緩沖的,所以父進程在執(zhí)行了第一個printf語句后,"Start fork..."還保存在緩沖區(qū)中,執(zhí)行fork的時候,父進程緩沖區(qū)的數(shù)據(jù)也被復制到子進程中,子進程在刷新緩沖區(qū)的時候,輸出了從父進程復制來的"Start fork..."。
下面對程序進行一些修改:
1、如果把第7句改為:
fprintf(stdout,"%s","Start fork...\n");
$./test
Start fork...
Child process.
Parent process.
說明當前環(huán)境下printf是行緩沖的。
把修改過的程序的執(zhí)行結果重定向到文件中:
$./test > temp
$cat temp
Start fork...
Child process.
Start fork...
Parent process.
這說明將printf輸出結果重定向到文件的時候就變了全緩沖.
2、如果在第7行以后加入一句:
fflush(stdout);
$./test > temp
$cat temp
Start fork...
Child process.
Parent process.
我們用fflush強制刷新緩沖區(qū),這樣父進程緩沖區(qū)被清空。我們在fork之前一般都要用fflush(NULL)清空所有流。
3、我們把第7句改為:
fprintf(stderr,"%s","Start fork...");
$./test > temp
Start fork...
$cat temp
Child process.
Parent process.
把修改過的程序的執(zhí)行結果重定向到文件,把標準錯誤重定向到標準輸出:
$./test > temp 2>&1
$cat temp
Start fork...
Child process.
Parent process.
表明當前環(huán)境stderr的默認目標是終端,而且是不緩沖的.4、如果我們在第7句之前加入:
setvbuf(stdout, NULL, _IONBF, 0);
設置標準輸出為無緩沖。
$./test > temp
$cat temp
Start fork...
Child process.
Parent process.