次のCプログラムは、子プロセスと親プロセスの間の競合状態を示しています。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fork();
printf("\n 1234567890 \n");
return 0;
}
私の友人がそれを実行すると(Ubuntu)、予想される出力を取得します。これは混乱している1234567890sです。
一例:12312345645678907890
ところで、同じプログラムを自分のコンピュータで実行してみるとアーキテクチャLinux、そのような出力を提供しません。常に順番に。
1234567890
1234567890
いいねアーチLinux競争条件を避ける方法はいくつかありますが、私の考えでは障害を負うそのような機能を使用し、私の友人から出力を取得したいと思います。
答え1
このprintf
呼び出しは1つ以上のwrite(2)
システム呼び出しを実行し、処理される順序は実際の出力順序になります。 1つ以上(Cライブラリ内のバッファリングによって異なります)ラインバッファ出力(ターミナルに移動)を使用すると、2回の呼び出しを受け取ることができますwrite
。 1 つは初期改行の呼び出しで、もう 1 つは残りの呼び出しです。
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()
システムコールを再作成するか、システムコール内にカーネルコンポーネントを含める必要があります。