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

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

オペレーティングシステムの概念とAPUE理論

vfork() を使用すると、親プロセスは一時停止され、子プロセスは親プロセスのアドレス空間を使用します。 vfork()は書き込み時にコピーを使用しないため、子プロセスが親プロセスのアドレス空間内のページを変更すると、親プロセスが再開されると、変更されたページが親プロセスに表示されます。だから、vfork() は、子プロセスが親プロセスのアドレス空間を変更しないように注意して使用する必要があります。

vfork()は、子プロセスが作成された直後にexec()またはexit()が呼び出されたときに使用されるように作成されました。

最後の文章をどのように理解する必要がありますか?

vfork()呼び出しによって子プロセスが作成されたら、新しいプログラムをロードして親プロセスのアドレス空間を変更しませexec()んか?exec()

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

私は個人的にLinuxを好みます。

ありがとうございます。

答え1

vfork()呼び出しによって子プロセスが作成されたら、新しいプログラムをロードして親プロセスのアドレス空間を変更しませexec()んか?exec()

いいえ、exec()新しいプログラムは新しいアドレス空間を提供し、親アドレス空間は変更されません。例を見るexecPOSIXの機能に関する議論Linuxexecve()のマンページ

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

簡単exit()です。実行中のプログラム(ライブラリを含む)によってインストールされたシャットダウンフックを実行します。vfork()したがって、Linuxではより制限的です。それは規定する何かの目的を指します。_exit()どのいいえCライブラリのクリーンアップ機能を呼び出します。

vfork()正しい理解が難しいことが判明し、現在のPOSIX標準バージョンでは削除されました。posix_spawn()使用すべき

しかし、あなたでなければ本物あなたが何をしているのかを知る必要があります。いいえvfork()またはposix_spawn();をfork()使用してくださいexec()

上記のリンクされたLinuxのマンページは、より多くのコンテキストを提供します。

しかし、以前はfork(2) 呼び出し元のデータスペースの完全なコピーが必要でしたが、通常はexec(3)anの直後に行われたため、不要でした。したがって、効率を向上させるために、BSDは、親vfork() プロセスのアドレス空間を完全にコピーせずに呼び出しが発生または終了するまで、親プロセスのメモリと制御スレッドを借りるシステムコールを導入しましたexecve(2)。子プロセスがそのリソースを使用している間、親プロセスは一時停止します。の使用は vfork()難しいです。たとえば、親プロセスでデータを変更しないことは、レジスタにどの変数があるかを知ることに依存します。

答え2

を呼び出すとvfork()新しいプロセスが作成され、新しいプロセスは親プロセスのプロセスイメージ(スタックを除く)を借ります。子プロセスには独自の新しいスタックアスタリスクがありますが、呼び出された関数returnから始めることはできませんvfork()

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

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

次のようにグローバルデータを変更する:

  • malloc() または free() を呼び出します。

  • 標準入力および出力の使用

  • 信号設定の変更

  • 呼び出し関数のローカル以外の変数を変更しますvfork()

  • ...

を呼び出すと_exit()(重要なことは絶対に呼び出されないexit())、子プロセスが終了し、制御権が親プロセスに返されます。

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

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

重要:Linuxには実際の実装はありませんvfork()。 Linuxは、1988年にSunOS-4.0で導入されたCopy on Writeの概念vfork()に基づいて実装されました。fork()ユーザーがLinuxを使用していると信じるようにするために、Linuxは共有データを設定し、子がその機能の1つを呼び出さないvfork()ときに親を一時停止します。_exit()exec*()

vfork()したがって、Linuxは、誤ってカーネルの子プロセスのアドレス空間の説明が必要ないという事実から恩恵を受けません。これにより、aはvfork()より速くなりませんfork()。 real を実装するシステムでは、vfork()通常、-、Nearest、および - を使用するシェルよりも 3 倍速く、fork()パフォーマンスに影響を与えます。vfork()ksh93Bourne Shellcsh

exit()ed子から呼び出すべきではない理由は、呼び出し前にフラッシュされていないデータがある場合にstdioをフラッシュするためvfork()です。これは奇妙な結果を引き起こす可能性があります。exit()vfork()

注:posix_spawn()その上に実装されているため、vfork()OSvfork()から削除されません。誰かがLinuxvfork()では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()。親スタックの前の部分へのアクセスを許可する実装はありません。

関連情報