6 に答える
の目的は、子で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コピーオンライト技術が使用されます。
すでに述べたように、vforkmanページは違いについて明確です。このトピックforkでは、、、およびの適切な説明を提供しvforkます。cloneexec
fork以下は、vfork私が使用したLinux2.6.3x組み込みシステムで見落とされがちな違いです。
コピーオンライト技術をfork使用しても、親プロセスが使用するメモリを複製するのに十分なメモリがない場合は失敗します。たとえば、親プロセスが2 GBの常駐メモリ(つまり、使用されているだけでなく割り当てられているメモリ)を使用してforkいる場合、残りの空きメモリが2 GB未満になると、失敗します。単純なプログラムが必要な場合はイライラするexecので、その巨大な親アドレス空間は必要ありません。
vfork親アドレス空間を複製しないため、このメモリの問題はありません。子プロセスは、親プロセスを傷つけることなく、呼び出すexec*ことができるスレッドのように機能します。_exit
ここで指摘されているように、メモリページテーブルは複製されないため、実行時間は親プロセスが使用するメモリの量に影響されません。httpvfork : //blog.famzah.net/2009/11/20 / fork-gets-slower-as-parent-process-use-more-memory /forkvfork
したがって、パフォーマンスが重要であるか、メモリが制限されている状況では、vfork+が+exec*の代わりになります。問題は、安全性が低く、manページに将来廃止される可能性があると書かれていることです。forkexec*vfork
より安全でポータブルな解決策は、posix_spawnより高いレベルでより多くのオプションを提供する関数を調べることかもしれません。vfork渡すオプションに応じて、可能な場合は安全に使用します。+をうまく使用して、 +が私に与えていposix_spawnた厄介な「ダブルメモリチェックの問題」を克服することができました。forkexec
私のマニュアルページから
(POSIX.1から)vfork()関数はfork(2)と同じ効果がありますが、vfork()によって作成されたプロセスが、 vfork()から値を返すか、vfork()が呼び出された関数から戻るか、_exit(2)またはexec(3)ファミリーの関数の1つを正常に呼び出す前に他の関数を呼び出します。
vfork()はfork(2)とは異なり、子が終了するまで(通常は、_exit(2)を呼び出すか、異常に、致命的なシグナルの配信後に)、またはexecve(2)を呼び出します。 )。その時点まで、子はスタックを含むすべてのメモリを親と共有します。子は現在の関数から戻ったり、exit(3)を呼び出したりしてはなりませんが、_exit(2)を呼び出すことはできます。
一部のシステムには、元々fork()のオーバーヘッドの低いバージョンとして設計されたvfork()というシステムコールがあります。fork()はプロセスのアドレス空間全体をコピーする必要があり、したがって非常にコストがかかるため、vfork()関数が導入されました(3.0BSDで)。
ただし、vfork()が導入されてから、fork()の実装は大幅に改善されました。特に、両方のプロセスが参照できるようにすることで、プロセスのアドレス空間のコピーが透過的に偽造される「コピーオンライト」が導入されました。それらのいずれかがそれを変更するまで、同じ物理メモリに。これにより、vfork()の正当性が大幅に削除されます。実際、システムの大部分は現在、vfork()の元の機能を完全に欠いています。ただし、互換性のために、vfork()セマンティクスのすべてをエミュレートしようとせずに、単にfork()を呼び出すvfork()呼び出しが存在する場合があります。
結果として、fork()とvfork()の違いを実際に利用することは非常に賢明ではありません。実際、なぜ必要なのかを正確に理解していない限り、vfork()を使用することはおそらく賢明ではありません。
2つの基本的な違いは、vfork()を使用して新しいプロセスが作成されると、親プロセスが一時的に中断され、子プロセスが親のアドレス空間を借用する可能性があることです。この奇妙な状況は、子プロセスが終了するか、execve()を呼び出すまで続き、その時点で親プロセスが続行します。
これは、vfork()の子プロセスが、親プロセスの変数を予期せず変更しないように注意する必要があることを意味します。特に、子プロセスはvfork()呼び出しを含む関数から戻ってはならず、exit()を呼び出してはなりません(終了する必要がある場合は、_exit()を使用する必要があります)。実際、これは子にも当てはまります。通常のfork()の)。
2つの基本的な違いは、で新しいプロセスが作成されるとvfork()、親プロセスが一時的に中断され、子プロセスが親のアドレス空間を借用する可能性があることです。この奇妙な状況は、子プロセスが終了するか、を呼び出すまで続き、execve()その時点で親プロセスが続行します。
これは、の子プロセスがvfork()親プロセスの変数を予期せず変更しないように注意する必要があることを意味します。特に、子プロセスはvfork()呼び出しを含む関数から戻ってはならず、呼び出してはなりません
exit()(終了する必要がある場合は_exit();
、実際に使用する必要があります。これは、通常の子にも当てはまりますfork())。
ただし、vfork()導入以来、の実装はfork()大幅に改善されました。特に、「コピーオンライト」の導入により、両方のプロセスが同じ物理メモリを参照できるようにすることで、プロセスのアドレス空間のコピーが透過的に偽造されます。それらのいずれかがそれを変更します。vfork();これにより、実際
の正当性が大幅に失われ、システムの大部分が元の機能をvfork()完全に欠いているようになりました。ただし、互換性のために、すべてのセマンティクスをエミュレートしようとせずvfork()に単に呼び出す呼び出しがまだ存在する場合があります。fork()vfork()
結果として、との違いを実際に利用することは非常に賢明ではありませfork()んvfork()。vfork()確かに、なぜ使いたいのかを正確に理解していない限り、使用するのはおそらく賢明ではありません。