2011-01-20 143 views
8

我正在看fork上的一些簡單的代碼,並決定自己嘗試一下。我編譯並從Emacs內部運行它,並獲得了不同的輸出到在Bash中運行它所產生的輸出。當我管輸出時,爲什麼我的分岔程序的輸出不同?

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    if (fork() != 0) { 
    printf("%d: X\n", getpid()); 
    } 

    if (fork() != 0) { 
    printf("%d: Y\n", getpid()); 
    } 

    printf("%d: Z\n", getpid()); 
} 

我用gcc編譯它,然後跑的a.out從在Emacs,以及它管道傳輸到cat,並grep .,並得到了這一點。

2055:X
2055:Y
2055位:Z
2055:X
2058位:Z
2057:Y
2057位:Z
2059位:Z

這是不對的。剛剛從猛砸運行它,我得到(我希望)

2084:X
2084:Y
2084位:Z
2085:Y
2085位:Z
2087位:Z
2086: ž

編輯 - 錯過了一些新行

發生了什麼事?

+0

你爲什麼通過任何東西(特別是「貓」,它根本不會做任何事情)管道結果? - 哦,等待它是引入奇怪的管道...嗯... – Pointy 2011-01-20 17:08:31

+0

我可以重現這一點,所以它不是宇宙射線或任何東西。耐人尋味。請注意,前一個輸出中缺少一個PID(2056);這可能是`cat`的PID。 – Thomas 2011-01-20 17:11:11

回答

11

不同進程寫入其輸出的順序完全不可預知。所以唯一令人驚訝的是,有時「X」打印語句有時會發生兩次。

我認爲這是因爲有時在第二個fork(),包含「X」的輸出行在輸出緩衝區中,需要刷新。所以兩個進程最終都會打印出來由於getpid()已被調用並轉換爲字符串,因此它們將顯示相同的pid。

我能夠複製多條「X」線,但如果在第二個fork()之前添加fflush(stdout);,我總是隻能看到一條「X」線,總是總共7條線。

8

我想我知道發生了什麼。輸出爲tty時,stdio緩衝區會有所不同,而輸出是管道或文件時。子進程繼承父緩衝區。當它們被刷新時,你可以獲得雙重輸出。

如果你把每printf()呼叫後立即加入

fflush(stdout); 

,你就會明白我的意思。

有趣的是,當標準輸出是一個tty設備時它是不同的。這可能是因爲圖書館知道這意味着什麼,並且在每次換行之後刷新,或者類似的東西。

6

所以我想你是想知道爲什麼你會得到多個「X」?

這是因爲緩衝輸出正在刷新兩次。

當您管道程序的輸出時,stdio庫會識別您的輸出不是終端,並且它切換到塊緩衝而不是行緩衝。因此,當過程叉和現在父母和孩子都有待處理的輸出時,還沒有任何輸出。

3

如果您已經使用stdout在所有分叉之前,你必須電話之前fflush(stdout)fork()(同樣地爲你使用任何其他輸出FILE S)。不這樣做會導致未定義的行爲。您看到的效果來自stdout,當它連接到終端時,它是線路緩衝,但當它連接到管道時,完全緩衝。這不是必需的,但是由標準(POSIX)推薦。

相關問題