web-dev-qa-db-ja.com

fork()とvfork()の違いは何ですか?

Fork()とvfork()の違いを詳しく理解したいと思います。マニュアルページを完全に消化できませんでした。

また、同僚のコメントの1つを明確にしたいと思います。「現在のLinuxでは、vfork()はありません。呼び出しても、内部的にfork()を呼び出します。」

13
Sen

マニュアルページは通常、簡潔なリファレンスドキュメントです。 Wikipedia は、概念的な説明を参照するのに適した場所です。

Forkはプロセスを複製します。親プロセスとほぼ同じ子プロセスが作成されます(最も明らかな違いは、新しいプロセスのプロセスIDが異なることです)。特に、フォークは(概念的に)すべての親プロセスのメモリをコピーする必要があります。

これはかなりコストがかかるため、vforkはコピーが不要な一般的な特殊なケースを処理するために発明されました。多くの場合、子プロセスが最初に行うのは、新しいプログラムイメージを読み込むことです。そのため、次のようになります。

if (fork()) {
    # parent process …
} else {
    # child process (with a new copy of the process memory)
    execve("/bin/sh", …);  # discard the process memory
}

execve呼び出しは新しい実行可能プログラムをロードし、これはプロセスのコードとデータメモリを新しい実行可能プログラムのコードと新しいデータメモリに置き換えます。したがって、forkによって作成されたメモリコピー全体は、まったく無駄でした。

したがって、 vfork 呼び出しが発明されました。メモリのコピーは作成しません。したがって、vforkは安価ですが、子プロセス内のプロセスのスタックまたはヒープ領域にアクセスしないようにする必要があるため、使いにくいです。親プロセスは実行を続けるため、読み取りでさえ問題になる可能性があることに注意してください。たとえば、次のコードは機能しません(子または親が最初にタイムスライスを取得するかどうかによって、機能しない場合があります)。

if (vfork()) {
    # parent process
    cmd = NULL; # modify the only copy of cmd
} else {
    # child process
    execve("/bin/sh", "sh", "-c", cmd, (char*)NULL);  # read the only copy of cmd
}

Vforkの発明以来、より良い最適化が発明されました。 Linuxを含む最近のほとんどのシステムでは、 copy-on-write の形式を使用しています。この場合、プロセスメモリ内のページはforkの呼び出し時にコピーされませんが、後で親または子が最初にページに書き込みます。つまり、各ページは共有として開始され、いずれかのプロセスがそのページに書き込むまで共有されたままになります。書き込みを行うプロセスは、(同じ仮想アドレスを持つ)新しい物理ページを取得します。 forkvforkが使用可能な場合にコピーを作成しないため、コピーオンライトではvforkがほとんど役に立たなくなります。

Linuxはvforkを保持します。 forkシステムコールは、実際のメモリをコピーしなくても、プロセスの仮想メモリテーブルのコピーを作成する必要があります。 vforkはこれを行う必要さえありません。ほとんどのアプリケーションでは、パフォーマンスの向上はごくわずかです。

fork()vfork()のシステムコールは異なります。

fork() syscallは、別々のメモリを持つ2つの同一のプロセスを生成します。 vfork() syscallは、同じメモリを共有する2つのプロセスを生成します。

vfork()を使用すると、親は子が終了するのを待ちます。親は、プログラムが共有している変数から継承します。したがって、子が呼び出された後、子の内部で変更されたすべての変数は、親の内部でも変更されます。

詳細については ここ をクリックしてください

2
Yogeesh H T