3

私はfork/vfork関数で少し遊んでいますが、私には困惑することがあります。スティーブンスの本には次のように書かれています。

図8.3では、exitではなく_exitを呼び出していることに注意してください。

セクション7.3で説明したように、_exitは標準のI/Oバッファのフラッシュを実行しません。代わりにexitを呼び出すと、結果は不確定になります。標準のI/Oライブラリの実装によっては、出力に違いが見られない場合や、親のprintfからの出力が消えている場合があります。子がexitを呼び出すと、実装は標準のI/Oストリームをフラッシュします。これがライブラリによって実行される唯一のアクションである場合、子が_exitを呼び出した場合に生成される出力との違いはわかりません。ただし、実装が標準I / Oストリームも閉じる場合、標準出力のFILEオブジェクトを表すメモリはクリアされます。子は親のアドレス空間を借用しているため、親が再開してprintfを呼び出すと、出力は表示されず、printfは-1を返します。子は親のファイル記述子配列のコピーを取得するため、親のSTDOUT_FILENOは引き続き有効であることに注意してください(図8.2に戻るを参照)。最新のexitの実装のほとんどは、ストリームを閉じるのに苦労することはありません。プロセスが終了しようとしているため、カーネルはプロセスで開いているすべてのファイル記述子を閉じます。ライブラリでそれらを閉じると、何のメリットもなくオーバーヘッドが追加されます。

そこで、printfエラーが発生するかどうかをテストしようとしましたが、vforkのマニュアルには次のようなものがあります。

開いているすべてのstdio(3)ストリームがフラッシュされ、閉じられます。tmpfile(3)によって作成されたファイルは削除されます。

しかし、このプログラムをコンパイルして実行すると、次のようになります。

  #include<stdio.h>
  #include<stdlib.h>
  #include<unistd.h>
  #include<sys/types.h>
  #include<sys/wait.h>

  int main()
{
  int s;
  pid_t ret;
  if (vfork() == 0)
  {
      //abort();
      exit(6);
  }
  else
  {
      ret=wait(&s);
      printf("termination status to %d\n",s);
      if (WIFEXITED(s))
          printf("normalnie, status to %d\n",WEXITSTATUS(s));
  }
  return 0;
}

すべてが正常に機能しています。printfエラーは発生しません。何故ですか?

4

1 に答える 1

3

引用した段落の最後には、次のように書かれています。

exit の最新の実装のほとんどは、わざわざストリームを閉じる必要はありません。プロセスが終了しようとしているため、カーネルはプロセスで開いているすべてのファイル記述子を閉じます。ライブラリでそれらを閉じると、オーバーヘッドが増えるだけで、何のメリットもありません。

これはおそらく起こっていることです。OS は実際にはストリームを閉じません (ただし、おそらくフラッシュします)。

重要なのはexit、ここで何をするかではなく、その根底にあるコンセプトです。子は親のメモリとスタック フレームを共有しています。つまり、子は、親が予期していなかったものを非常に簡単に変更できます。これにより、親が再び実行を開始したときに、親がクラッシュしたり、誤動作したりする可能性があります。のマニュアルページにvforkは、プロセスが実行できるのは呼び出しexit()またはexec. 実際、子はメモリを割り当てたり、変数を変更したりすることさえすべきではありません。

この影響を確認するには、vfork呼び出しを関数内に配置して、子にいくつかの変数を返すか変更させて、何が起こるかを確認します。

于 2012-04-05T21:20:14.780 に答える