4

での作業を学んでfork()いますが、いくつか質問があります。

次のコードを検討してください。

#include <stdio.h>
#include <unistd.h>

int main()
{
   int i;

   for(i = 0; i < 5; i++)
   {
      printf("%d", i);

      if((i%2)==0)
         if(fork())
            fork();
   }
}

端末に出力すると、期待する結果が得られます(つまり:) 0,1,1,1,2,2,2,...。しかし、ファイルに出力すると、結果は完全に異なります。

  • ケース1:(端末への出力、例:)./a.out

    結果は次のとおりです。0,1,1,1,2,2,2,...

  • ケース2:(ファイルへの出力、例./a.out > output_file:)

    結果は次のとおりです。0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,...

なんでこんな感じ?

4

4 に答える 4

6

ファイルに出力すると、stdioライブラリはアウトバウンドビットを自動的にブロックバッファリングします。

プログラムが呼び出しexit(2)たり、残りのバッファリングされたビットから戻ったりすると、main(),フラッシュされます。

このように出力が少ないプログラムでは、宛先がttyでない場合からの復帰後に、すべてのI/Oが発生します。main(),これにより、I/O操作のパターンと順序がすべて単独で変更されることがよくあります。

この場合、結果は一連のfork()呼び出しによってさらに複雑になります。これにより、各子イメージで部分的にいっぱいになり、まだフラッシュされていないI/Oバッファーが複製されます。

プログラムを呼び出す前に、fork(),まずfflush(3)を使用してI/Oをフラッシュする場合があります。このフラッシュが実行されない場合は、同じビットが複数回出力されないようにするために、 1つ(通常は子)を除くすべてのプロセスを_exit(2)代わりに、exit(3)またはそこから戻すことができます。main(),(_exit(2)はexitシステム呼び出しを行うだけです。)

于 2013-01-22T17:57:06.053 に答える
4

プログラムのfork()内部ifブロックは2回実行されます。これは、フォークが成功すると、プログラムは2つのプロセス(プロセスとプロセス)によって制御されるためです。したがって、fork()内部ifブロックは、子プロセスと親プロセスの両方によって実行されます。したがって、2つの異なるプロセスによって制御され、実行の順序が不明であるため、予想とは異なる出力になります。すなわち。子または親のいずれかが、それぞれの後に最初に実行できますfork()

出力とファイルの動作の違いについて。という訳だ。

バッファに書き込んだ内容(file(disk)最終的に書き込まれる)は、ファイル(ディスク)にすぐに書き込まれるとは限りません。ほとんどの場合、main()の実行が完了した後にのみディスクにフラッシュされます。一方、 main()の実行中に端末に出力されます。

ディスク内のファイルに書き込む前に、kernel実際にデータをバッファにコピーし、後でバックグラウンドで、カーネルはすべてのダーティバッファを収集し、それらを最適にソートしてファイル(ディスク)に書き込みます。これはライトバックと呼ばれます。また、カーネルが書き込みをより多くのアイドル期間に延期し、多くの書き込みをまとめてバッチ処理できるようにします。

このような動作を回避するには、プログラムで3つの異なる条件チェックを使用することをお勧めします。fork()

int pid;
if((pid = fork()) == -1 )
{ //fork unsuccessful 
 }
else if ( pid > 0)
{ //This is parent
 }
else
{//This is child
 }
于 2013-01-22T17:58:54.057 に答える
2

バッファリングされたストリームは、時々奇妙な結果を生み出す可能性があります...特に同じバッファリングされたストリームを使用する複数のプロセスがある場合。バッファを強制的にフラッシュすると、さまざまな結果が表示されます。

int main()
{
   int i;
   FILE * fd = fopen(yourfile, "w");
   for(i = 0; i < 5; i++)
   {
      fprintf(fd, "%d", i);
      fflush(fd);
      if((i%2)==0)
         if(fork())
            fork();
   }
}

また、デバッグの目的で、プロセスのIDをダンプして、どのプロセスがどのプロセスを生成するかを確認し、何が起こっているのかをよりよく理解できるようにすると便利な場合があります。getpid()それであなたを助けることができます。

于 2013-01-22T18:07:03.223 に答える
1

フォークするときに端末とファイルで出力が異なるのはなぜですか?

C標準ライブラリ関数は、高速化のために内部バッファリングを使用します。ほとんどの実装では、ファイルストリームに完全にバッファリングされたIO、stdin / stdoutにラインバッファリング、stderrにバッファリングされていないIOを使用します。

したがって、問題はさまざまな方法で解決できます。

  1. フォーク経由の前に明示的なバッファフラッシュを使用するfflush(3)
  2. バッファタイプを手動で設定しますsetvbuf(3)
  3. write(2)stdlibの代わりに使用するprintf(3)
  4. *****stderr経由でデフォルトでに出力fprintf(3)
  5. ******_exit(2)の代わりにフォークされたプロセスで終了しますexit(3)

次の場合、最後の2つは期待どおりに機能しない可能性があり
ます。*実装がデフォルトでstderrへのバッファなし書き込みを使用しない(ISO Cで必要)
**子にデフォルトを超えるバッファサイズを書き込み、自動的にフラッシュされた場合。

PS。繰り返しになりますが、標準ライブラリ関数とバッファリングについての深い知識が必要な場合は、W。リチャードスティーブンスとスティーブンA.ラゴによるUNIX環境での高度なプログラミング(第2版)を読むことをお勧めします。

PPS。ところで、あなたの質問は、C /C++プログラマーの立場で非常に人気のあるインタビューの質問です。

于 2013-01-23T06:02:12.433 に答える