GNU/Linux >> Linux の 問題 >  >> Linux

子プロセスが作成直後に exec() または exit() を呼び出すときに vfork() が使用されるのはなぜですか?

<ブロック引用>

vfork() で作成した子プロセスの場合 exec() を呼び出します 、しない exec() 新しいプログラムをロードして、親プロセスのアドレス空間を変更しますか?

いいえ、exec() 新しいプログラムに新しいアドレス空間を提供します。親アドレス空間は変更されません。たとえば、 exec の議論を参照してください POSIX の関数、および Linux execve()

<ブロック引用>

vfork() によって作成された子プロセスが exit() を呼び出す場合、exit() は子プロセスを終了するときに親プロセスのアドレス空間を変更しませんか?

プレーン exit() might – 実行中のプログラム (ライブラリを含む) によってインストールされた終了フックを実行します。 vfork() より制限的です。したがって、Linux では、_exit() の使用が義務付けられています。 しない C ライブラリのクリーンアップ関数を呼び出します。

vfork() 正しく理解するのは非常に難しいことが判明しました。現在のバージョンの POSIX 標準では削除されており、posix_spawn() 代わりに使用する必要があります。

ただし、本当に すべきではない vfork() のいずれかを使用します または posix_spawn();古き良き fork() にこだわる そして exec() .

上記のリンクにある Linux のマンページは、より多くのコンテキストを提供します:

<ブロック引用>

しかし、昔は fork(2) 通常は直後に exec(3) 終わらせる。したがって、効率を高めるために、BSD は vfork() を導入しました。 このシステム コールは、親プロセスのアドレス空間を完全にはコピーしませんでしたが、execve(2) の呼び出しまで、親プロセスのメモリと制御スレッドを借用しました。 または出口が発生しました。子がそのリソースを使用している間に、親プロセスが中断されました。 vfork() の使用 トリッキーでした:たとえば、親プロセスのデータを変更しないことは、どの変数がレジスターに保持されているかを知ることに依存していました。


vfork() を呼び出した場合 、新しいプロセスが作成され、その新しいプロセスは、スタックを除いて親プロセスのプロセス イメージを借用します。子プロセスには独自の新しいスタック スターが与えられますが、return は許可されません。 vfork() を呼び出した関数から .

子が実行されている間、子が親のアドレス空間を借用したため、親プロセスはブロックされます。

何をするにしても、スタックにアクセスするだけで、子のプライベート スタックのみが変更されます。ただし、グローバル データを変更すると、共通データが変更されるため、親にも影響します。

グローバル データを変更するものは次のとおりです。

  • malloc() または free() の呼び出し

  • 標準入出力の使用

  • 信号設定の変更

  • vfork() を呼び出した関数に対してローカルではない変数の変更 .

  • ...

_exit() を呼び出したら (重要、exit() は絶対に呼び出さないでください )、子は終了し、制御は親に戻されます。

exec*() から関数を呼び出した場合 新しいアドレス空間は、新しいプログラム コード、新しいデータ、および親からのスタックの一部で作成されます (以下を参照)。これが準備できると、子は子からアドレス空間を借りなくなりますが、独自のアドレス空間を使用します。

コントロールのアドレス空間が別のプロセスで使用されなくなったため、コントロールは親に返されます。

重要:Linux では、実際の vfork() はありません。 実装。 Linux はむしろ vfork() を実装しています Copy on Write fork() に基づく 1988 年に SunOS-4.0 で導入された概念。 vfork() を使用しているとユーザーに信じ込ませるために 、Linux は共有データをセットアップし、子が _exit() を呼び出していない間、親を一時停止します または exec*() のいずれか 関数。

したがって Linux は、実際の vfork() が カーネルで子のアドレス空間記述をセットアップする必要はありません。これは vfork() になります fork() より速くない .実際の vfork() を実装するシステム 、通常は fork() よりも 3 倍高速です vfork() を使用するシェルのパフォーマンスに影響します - ksh93 、最近の Bourne Shellcsh .

exit() に電話してはいけない理由 vfork() から ed の子は exit() です vfork() を呼び出す前の時間からフラッシュされていないデータがある場合に stdio をフラッシュします .これにより、奇妙な結果が生じる可能性があります。

ところで:posix_spawn() vfork() の上に実装されています 、だから vfork() OS から削除される予定はありません。 Linux は vfork() を使用しないことが言及されています posix_spawn() の場合 .

スタックについては、ドキュメントはほとんどありません。Solaris のマニュアル ページには次のように記載されています。

 The vfork() and vforkx() functions can normally be used  the
 same  way  as  fork() and forkx(), respectively. The calling
 procedure, however, should not return while running  in  the
 child's  context,  since the eventual return from vfork() or
 vforkx() in the parent would be to a  stack  frame  that  no
 longer  exists. 

したがって、実装は好きなことを行うことができます。 Solaris の実装では、vfork() を呼び出す関数のスタック フレームに共有メモリを使用します。 .親からスタックの古い部分へのアクセスを許可する実装はありません。


Linux
  1. プロセスが終了したときのデフォルトの終了コード?

  2. 子プロセスのPgidが親のPidではないのはなぜですか?

  3. 実行後にBashスクリプトが終了しないのはなぜですか?

  1. 親が終了した後に子プロセスを終了させる方法は?

  2. fork()、vfork()、exec()、clone()の違い

  3. Linuxで親プロセスが強制終了された後、子プロセスがまだ生きているのはなぜですか?

  1. このシェル パイプラインが終了するのはなぜですか?

  2. Bash:子スクリプトが SIGINT をトラップするときに親スクリプトが SIGINT で終了しないのはなぜですか?

  3. システムが現在プロセスで使用されていると言っているときに、Linuxでユーザーを削除するにはどうすればよいですか