web-dev-qa-db-ja.com

fork()ブランチが予想よりも多いですか?

次のコードを検討してください。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    int i;
    for(i = 0; i < 2; i++)
    {
        fork();
        printf(".");
    }
    return 0;
}

このプログラムは8つのドットを出力します。どうしてそれが可能ですか?代わりに6つのドットがありませんか?

186

fork()プリミティブは、しばしば想像力を伸ばします。それがわかるまで、各操作が何であるかを紙に書き留めて、プロセスの数を説明する必要があります。 fork()が現在のプロセスのほぼ完璧なコピーを作成することを忘れないでください。最も重要な違い(ほとんどの目的)は、fork()の戻り値が親と子で異なることです。 (このコードは戻り値を無視するため、違いはありません。)

したがって、最初は1つのプロセスがあります。これにより、2番目のプロセスが作成され、どちらもドットとループを出力します。 2回目の反復で、それぞれが別のコピーを作成するため、4つのプロセスがドットを出力して終了します。したがって、ご想像のとおり、6つのドットを簡単に説明できます。

ただし、printf()が実際に行うのは、その出力をバッファリングすることです。したがって、プロセスが2つしかなかったときの最初のドットは、書き込まれたときに表示されません。これらのドットはバッファーに残ります。これはfork()で複製されます。バッファリングされたドットが表示されるのは、プロセスが終了する直前です。バッファードドットを印刷する4つのプロセスに加えて、新しいプロセスは8つのドットを提供します。

その動作を回避したい場合は、fflush(stdout);の後にprintf()を呼び出します。

245
wallyk

出力ストリームのコミットされていないバッファがあります。 stdoutは行バッファリングされ、バッファはプロセスの残りの部分とともに複製されます。プログラムが終了すると、コミットされていないバッファが2回書き込まれます(プロセスごとに1回)。両方を使用して

printf("a\n");

そして

printf("a "); fflush(stdout);

問題を示さないでください。

最初の例では、出力ストリームバッファーにそれぞれ2つのドットを持つ4つのプロセスを作成します。各ストリームが終了すると、バッファをフラッシュし、8つのドットを生成します。

70
thiton

i = 0の場合

Process_1:バッファされたテキスト= 1ドット

Process_2(Process_1により作成):バッファリングされたテキスト= 1ドット

i = 1の場合

Process_3(Process_1によって作成):Process_1から1つのバッファリングされたドットを継承し、1つのドットを単独で印刷します。合計でProcess_3は2ドットを印刷します。

Process_4(Process_2で作成):Process_2から1つのバッファリングされたドットを継承し、1つのドットを単独で印刷します。合計でProcess_4は2ドットを印刷します。

Process_1:2つのドットを印刷します(i = 0の場合は1つのバッファードドット、i = 1の場合は別のドット)

Process_2:2つのドットを印刷します(i = 0の場合は1つのバッファードドット、i = 1の場合は1つのドット)

最終出力:8ドット。 :)

2
Tauseef