#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main( int argc, char *argv[] ){
FILE *fptr;
pid_t pid;
fptr = fopen("Shared File.txt", "a");
pid = fork();
if( pid > 0 ){ // parent process
int counter = 0;
while( counter < 10 ){
fprintf(fptr, "a");
++counter;
}
wait(NULL);
}
else{
int counter = 0;
while( counter < 5 ){
fprintf(fptr, "b");
++counter;
}
}
return 0;
}
このコードを実行すると、コードによって生成されたファイルに次のメッセージが含まれます。 bbbbbaaaaaaaaaa
このコードを実行するたびに同じメッセージが表示されます。書き込みファイルを混在順に処理しないのはなぜですか?
オペレーティングシステムが最初にサブプロセスを終了しようとしたのはなぜですか?
メッセージに対する私の期待は次のとおりです。プロセス間の継続的な移行がないbaabbaaabaaabaa。
答え1
父と息子の間のスケジュールは(少なくとも)子プロセスが実行されるときそしてフォークシステムコールはどのように機能しますか?。
ただし、この場合でも通常のファイルへの書き込みをstdio
使用しています。fprintf()
デフォルトでは、stdio
システムコールのオーバーヘッドを節約するのに十分なデータが書き込まれるまで、出力は通常のファイルにバッファリングされます。 x86 Linuxでは通常4096バイトのチャンクで書かれているようですが、バッファリングを手動で設定しないと期待できません(参照)setbuf()
そして友達)。
strace
プログラムによって実行されたシステムコールの表示などのコマンドを使用して、これを確認できます。
したがって、どのプロセスが最初に実行されるかを予測することはできませんが、この場合、sが連続して記録され、a
sb
も記録されることを予測できます。あなたは、bbbbbaaaaaaaaaa
またはいずれかを取得することができaaaaaaaaaabbbbb
、どちらを得るかは、ほとんど運の問題です。
答え2
私は基本的に@ikkachuに同意します。
あなたが得るものbbbbbaaaaaaaaaa
またはaaaaaaaaaabbbbb
予測できるもの。オペレーティングシステムは子プロセスが完了するのを待ち、親wait(NULL)
プロセスが終了します。終了時にバッファがフラッシュされると、サブプロセスは最初に書き込みを開始します。
ただし、予測可能なバッファに依存しないでください。必要に応じて明示的な更新を使用してください。
答え3
ユーザーilkkachuは、バッファリングが出力にどのように影響するかについてよく説明しました。私の答えは、バッファリングを削除すると(たとえば、fprintf
呼び出しをペアに置き換えるとどうなるかを説明します。この場合、sとsはwrite
厳密に交互に表示されます。これはペアの呼び出しによってスケジュールが変更されるためです)プロセスに書き込むと、プロセスがブロックされてからその順番が渡されます。a
b
write
writeを呼び出すと、何が起こるのかを想像してみましょう。いいえ詰まった。その後、時間スケールを考慮する必要があります。最新のプロセッサは毎秒数十億の命令を実行できますが、予約頻度は通常100 Hzから1000の間であるため、一度に1つまたは2つではなくsとa
sの実行時間が得られます。b
ヘルツ。プロセスはプリエンプションされ、他のプロセスが実行されるようにスケジュールされる前に、最大数千万のコマンドを実行できます。システムコールのオーバーヘッドを考慮しても、これは連続したa
sまたはb
sの非常に長い文字列を印刷するためのプロセス時間を提供します。
答え4
ikkachuとJohanは自分の行動を観察する理由を非常によく説明したので、各プロセスがストリームをフラッシュしてしばらく休止するようにプログラムを少し書き直しました(各スレッドが毎回異なる方法で視差を置いて機会を得ましたように)。すれ違った効果をより明確に確認してください。
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
FILE *fptr = stdout;
pid_t pid;
int counter = 0;
pid = fork();
if(pid > 0) { // parent process
while(counter++ < 10) {
fprintf(fptr, "aa");
fflush(fptr);
sleep(1);
}
wait(NULL);
puts("");
} else {
while(counter++ < 5) {
fprintf(fptr, "bbbb");
fflush(fptr);
sleep(1);
}
}
}
複数回実行すると、時々異なる結果が表示されます。
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbbbbbaaaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa