次のコードを検討してください。
#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つのドットがありませんか?
fork()
プリミティブは、しばしば想像力を伸ばします。それがわかるまで、各操作が何であるかを紙に書き留めて、プロセスの数を説明する必要があります。 fork()が現在のプロセスのほぼ完璧なコピーを作成することを忘れないでください。最も重要な違い(ほとんどの目的)は、fork()
の戻り値が親と子で異なることです。 (このコードは戻り値を無視するため、違いはありません。)
したがって、最初は1つのプロセスがあります。これにより、2番目のプロセスが作成され、どちらもドットとループを出力します。 2回目の反復で、それぞれが別のコピーを作成するため、4つのプロセスがドットを出力して終了します。したがって、ご想像のとおり、6つのドットを簡単に説明できます。
ただし、printf()
が実際に行うのは、その出力をバッファリングすることです。したがって、プロセスが2つしかなかったときの最初のドットは、書き込まれたときに表示されません。これらのドットはバッファーに残ります。これはfork()で複製されます。バッファリングされたドットが表示されるのは、プロセスが終了する直前です。バッファードドットを印刷する4つのプロセスに加えて、新しいプロセスは8つのドットを提供します。
その動作を回避したい場合は、fflush(stdout);
の後にprintf()
を呼び出します。
出力ストリームのコミットされていないバッファがあります。 stdoutは行バッファリングされ、バッファはプロセスの残りの部分とともに複製されます。プログラムが終了すると、コミットされていないバッファが2回書き込まれます(プロセスごとに1回)。両方を使用して
printf("a\n");
そして
printf("a "); fflush(stdout);
問題を示さないでください。
最初の例では、出力ストリームバッファーにそれぞれ2つのドットを持つ4つのプロセスを作成します。各ストリームが終了すると、バッファをフラッシュし、8つのドットを生成します。
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ドット。 :)