web-dev-qa-db-ja.com

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

fork()vfork() の違いは何ですか? vfork()fork()のように戻りますか?.

32
user507401

vforkの目的は、子でexec*のみを実行したい場合に、プロセスイメージ全体をコピーするオーバーヘッドを排除することでした。 exec*は子プロセスのイメージ全体を置き換えるため、親のイメージをコピーしても意味がありません。

if ((pid = vfork()) == 0) {
  execl(..., NULL); /* after a successful execl the parent should be resumed */
  _exit(127); /* terminate the child in case execl fails */
}

他の種類の使用では、vforkは危険で予測不可能です。

ただし、Linuxを含む現在のほとんどのカーネルでは、vforkの実装方法が原因で、forkの主な利点がなくなっています。 forkが実行されたときにイメージ全体をコピーするのではなく、コピーオンライト技術が使用されます。

36

すでに述べたように、vforkのmanページは違いについて明確です。この topic は、forkvforkcloneおよびexecについての適切な説明を提供します。

以下は、私が使用した一部のLinux 2.6.3x組み込みシステムで経験したforkvforkの見落とされがちな違いです。

コピーオンライト手法を使用しても、親プロセスが使用するメモリを複製するのに十分なメモリがない場合、forkは失敗します。たとえば、親プロセスが2 GBの常駐メモリ(つまり、使用されていて割り当てられていないメモリ)を使用している場合、空きメモリが2 GB未満になるとforkは失敗します。単純なプログラムをexecしたいだけで、そのため、巨大な親アドレス空間が必要になることはないので、それはイライラします。

vforkは、親アドレス空間を複製しないため、このメモリの問題はありません。子プロセスは、親プロセスに害を与えることなくexec*または_exitを呼び出すことができるスレッドのように機能します。

メモリページテーブルは複製されないため、vforkforkよりもはるかに高速であり、vforkの実行時間は、ここで指摘されているように、親プロセスが使用するメモリ量の影響を受けません。 : http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/

したがって、パフォーマンスが重要な場合やメモリが限られている場合は、vfork + exec*fork + exec*の代わりに使用できます。問題は、安全性が低く、manページにvforkが将来廃止される可能性が高いと記載されていることです。

より安全で移植性の高いソリューションは、より高いレベルでより多くのオプションを提供するposix_spawn関数を調べることです。渡すオプションに応じて、可能な場合はvforkを安全に使用します。私はposix_spawnを正常に使用でき、fork + execが与えていた厄介な「ダブルメモリチェックの問題」を克服できました。

いくつかのposix_spawnの例へのリンクがある、このトピックに関する非常に優れたページです。

23
dcoz

私のマニュアルページから

(POSIX.1から)vfork()関数はfork(2)と同じ効果がありますが、vfork()によって作成されたプロセスが、タイプpid_tの変数以外のデータを変更した場合の動作は未定義です。 vfork()からの戻り値、vfork()が呼び出された関数からの戻り、または_exit(2)またはexec(3)ファミリーの関数の1つを正常に呼び出す前に他の関数を呼び出します。

vfork()は、子が終了するまで(通常は_exit(2)を呼び出すか、異常に、致命的なシグナルが配信された後)、またはexecve(2 )。その時点まで、子はスタックを含むすべてのメモリを親と共有します。子は現在の関数から戻ったり、exit(3)を呼び出してはなりませんが、_exit(2)を呼び出すことができます。

4
SiegeX

一部のシステムには、システムコールvfork()があります。これは、元々はfork()のオーバーヘッドの低いバージョンとして設計されました。 fork()はプロセスのアドレス空間全体をコピーする必要があり、そのため非常にコストがかかるため、vfork()関数が導入されました(3.0BSD)。

ただし、vfork()が導入されてから、fork()の実装は大幅に改善されました。特に、「copy-on-write」の導入により、両方のプロセスが参照できるようにすることで、プロセスのアドレス空間のコピーが透過的に偽造されます。それらのいずれかが変更するまで、同じ物理メモリに。これにより、vfork()の正当性が大幅になくなります。実際、システムの大部分はvfork()の元の機能を完全に欠いています。ただし、互換性のために、すべてのvfork()セマンティクスをエミュレートしようとせずに、単にfork()を呼び出すvfork()呼び出しがまだ存在する場合があります。

その結果、fork()とvfork()の違いを実際に利用することは非常に賢明ではありません。実際、理由を正確に理解していない限り、vfork()を使用することはおそらく賢明ではありません。

2つの基本的な違いは、vfork()を使用して新しいプロセスが作成されると、親プロセスが一時的に中断され、子プロセスが親のアドレス空間を借用する可能性があることです。この奇妙な状況は、子プロセスが終了するか、execve()を呼び出すまで続き、その時点で親プロセスは続行します。

つまり、vfork()の子プロセスは、親プロセスの変数を予期せず変更しないように注意する必要があります。特に、子プロセスはvfork()呼び出しを含む関数から戻ってはならず、exit()を呼び出してはなりません(終了する必要がある場合は、_exit()を使用する必要があります);実際、これは子にも当てはまります。通常のfork()の場合)。

2
cpp-coder

ここ および wikipedia -から参照してください

一部のシステムでは、vfork()はfork()と同じです。 vfork()関数は、子プロセスが呼び出しプロセス(親プロセス)とコードとデータを共有できるという点でのみfork()と異なります。

1
Vishal

2つの基本的な違いは、vfork()を使用して新しいプロセスが作成されると、親プロセスが一時的に中断され、子プロセスが親のアドレススペースを借用する可能性があることです。この奇妙な状況が続く子プロセスが終了するか、execve()を呼び出すまで、その時点で親プロセスは続行します。

つまり、vfork()の子プロセスは、親プロセスの変数を予期せず変更しないように注意する必要があります。特に、子プロセスは、vfork()呼び出しを含む関数から復帰してはならず、exit()を呼び出してはなりません(終了する必要がある場合、実際には_exit();を使用する必要があります) 、これは通常の子にも当てはまりますfork())。

ただし、vfork()が導入されてから、fork()の実装は大幅に改善されました。特に、「copy-on-write」の導入によりプロセスアドレスのコピースペースは、どちらかのプロセスが変更するまで、両方のプロセスが同じ物理メモリを参照できるようにすることで、透過的に偽造されます。これにより、vfork();の正当性が大幅に排除されます。 vfork()完全に。ただし、互換性のために、vfork()セマンティクスのすべてをエミュレートしようとせずに、単にfork()を呼び出すvfork()呼び出しがまだ存在する場合があります。

その結果、fork()vfork()の違いを実際に利用することは非常に賢明ではありません。実際、なぜそうしたいのか正確に知らない限り、vfork()を使用することはおそらく賢明ではありません。

1
Rajesh Pal