
次の C プログラムは、子プロセスと親プロセス間の競合状態を説明するものです。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fork();
printf("\n 1234567890 \n");
return 0;
}
友人がそれを実行すると(ウブントゥ)すると、予想通りの出力が得られるが、これは1234567890の並びである。
一例:12312345645678907890
しかし、同じプログラムを私のアーチリナックス、そのような出力は決して出ません。常に次々に出力されます。
1234567890
1234567890
私はそれが好きですアーチLinux競合状態を回避する方法がありますが、無効にするそのような機能はなく、友人と同じ出力を得たいと思っています。
答え1
このprintf
呼び出しでは 1 つ以上のwrite(2)
システム コールが実行され、それらの処理順序が実際の出力順序になります。1 つまたは複数なのは、C ライブラリ内のバッファリングに依存するためです。行バッファリングされた出力 (端末に送信される) では、write
最初の改行用に 1 回、残り用に 1 回、合計 2 回の呼び出しが行われる可能性があります。
write(1, "\n", 1);
write(1, " 1234567890 \n", 13);
呼び出しの間に別のプロセスがスケジュールされ、最初に 2 つの空行が与えられ、次に数字の行が与えられる可能性がありますが、あまり多くの処理が行われていないことを考えると、負荷がかかっていないシステムではその可能性は低いです。
両方のプロセスがまったく同じものを印刷するため、一方が他方を中断しない限り、どちらが先に実行されても問題ないことに注意してください。
出力がファイルまたはパイプに送られる場合、デフォルトでは完全にバッファリングされるため、おそらく 1 回のwrite
呼び出し (プロセスあたり) のみが行われ、出力が混在する可能性はありません。
数字が 1 つずつ個別のシステム コールで出力されている場合、数字が混在する例は可能です。長さがわかっている静的文字列を印刷するときに、適切なライブラリ実装がなぜそれを行うのか理解するのは困難です。ループ内での書き込みが増えると、出力が混在する可能性が高くなります。
このようなもの:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
setbuf(stdout, NULL); /* explicitly unbuffered */
int x = fork();
for (i = 0 ; i < 500 ; i++) {
printf("%d", !!x);
}
if (x) {
wait(NULL);
printf("\n");
}
return 0;
}
以下のような出力が得られます。ほとんどの場合はそうなりますが、常にそうとは限りません。プロセスのスケジュール方法を決定するのはシステム次第です。予測不可能なため、通常は競合状態を回避しようとします。
111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111
111100000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000010000001001100
110000000011001100110011000000010011001100110000000100110011001100000001001
100110011000000010011001100110000000100110011001100000001001100110011000000
...
答え2
私の疑いは、fork()
システム コールが親プロセスまたは子プロセスのいずれかを長時間待機させ、他のプロセスが への呼び出しを終了してprintf()
、自身の に到達する前に文字列を出力に表示できるようにしているのではないかということですprintf()
。
ループ内で多数の文字列を出力すると、親プロセスと子プロセスの両方がループを同時に実行する時間がある場合、説明したように混在した出力が表示される可能性があります。
fork()
これを「修正」するには、システム コールまたはそれに関連するカーネル内のコンポーネントを書き直す必要がある可能性があります。