2011-01-20 17 views
8

私はフォークの簡単なコードを見ていて、自分で試してみることにしました。私はコンパイルして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: Z

編集 - いくつかの改行に

を逃しました

何が起こっているのですか?

+0

なぜあなたは何か(特に "cat"は何もしません)を介して結果をパイプしていますか? - オハイオ州、それは奇妙なことを紹介する配管です...うーん... – Pointy

+0

私はこれを再現することができますので、宇宙線や何かではありません。興味をそそる。前者の出力には1つのPID(2056)がないことに注意してください。おそらく 'cat'のPIDです。 – Thomas

+0

私はそれを数回実行しましたが、そのほとんどに欠落しているPIDはありませんでした。 – Squidly

答えて

11

異なるプロセスが出力を書き込む順序は完全に予測できません。驚くべきことは、たまに "X"プリントステートメントが時には2回起こることです。

これは、2番目のfork()に "X"を含む出力行が出力バッファにあり、フラッシュする必要があることが原因と考えています。両方のプロセスが最終的にそれを印刷します。 getpid()がすでに呼び出されて文字列に変換されているので、同じpidが表示されます。

複数の "X"行を再現することができましたが、fflush(stdout);を2番目のfork()の直前に追加すると、常に1つの "X"行と常に合計7行が表示されます。

8

私は何が起こっているか知っていると思います。 stdioバッファリングは、出力がttyのときとパイプのとき、またはファイルのときとは異なります。子プロセスは親バッファを継承します。彼らが洗い流されると、あなたは二重出力を得ることができます。

あなたは右の各printf()コールの後

fflush(stdout); 

を追加した場合、あなたは私が何を意味するかわかります。

興味深いのは、標準出力がttyデバイスの場合とは異なることです。ライブラリは、それが何を意味しているかを知っていて、各改行後にフラッシュするか、そのようなものかもしれません。

+0

本当に!各 'printf'がそれを解決した後に' fflush(stdout);を置く。出力バッファの内容はフォーク時にコピーされるので、バッファがフラッシュされると、同じバッファ出力が2回出力されます。 – Thomas

+0

これは正しいです。 'stdout'は対話型端末に書き込むときにデフォルトで行バッファされます(各' \ n'の後にフラッシュされます)が、パイプに書き込むときには完全にバッファされます。それぞれの 'fork()'の直前の単一の 'fflush(stdout);も動作します。 – caf

6

なぜ、複数の「X」が表示されているのだろうと思いますか?

これは、バッファリングされた出力が2回フラッシュされているためです。

プログラムの出力をパイプすると、stdioライブラリは出力がターミナルではないことを認識し、行バッファリングではなくブロックバッファリングに切り替えます。その結果、プロセスフォークが親と子の両方に保留中の出力を持つとき、まだ出力はありません。

3

あなたは(他の出力用と同様に、使用FILE秒)フォーク、あなた必見コールfflush(stdout)fork()前に前にすべてstdoutを使用している場合。そうしないと、の定義されていない動作が発生します。あなたが見ている効果は、stdoutのラインバッファーで、端末に接続されているときはが完全にバッファーされています。パイプに接続されている場合はです。これは必須ではありませんが、標準(POSIX)で推奨されています。

関連する問題