fork()は予想以上に分岐しますか?


186

次のコードを考えてみましょう。

#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つのドットがあるべきではありませんか?



回答:


245

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

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

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

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


12
ありがとう、私はバッファがfork()と重複することを知りませんでした。それはそのような奇妙な振る舞いを説明しています。
Nikolay Kovalenko 2012年

1
それは8ではなく10のドットを与えるべきではありませんか?4つの第2世代の子​​は、バッファリングされたドットを継承し、独自に追加してから、終了時にフラッシュします。合計8つのドットを印刷しますが、2つの第1世代のプロセスは、それぞれバッファリングされた1つのドットを持ち、終了時にそれらをフラッシュします。合計10を与える
psusi

12
第二世代のプロセスの@psusi一つである第一世代のプロセス。 fork()2を作成してから終了せず、1つだけプロセスを作成します。
Iskata

70

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

printf("a\n");

そして

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

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

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


2

i = 0の場合

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

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

i = 1の場合

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

Process_4(Process_2によって作成):Process_2から1バッファドットを継承し、1ドットを単独で印刷します。合計でProcess_4は2つのドットを印刷します。

Process_1:2つのドットを印刷します(i = 0の場合は1つのバッファリングドット、i = 1の場合はもう1つのドット)

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.