web-dev-qa-db-ja.com

fork()のコピーオンライトは複数のフォークをどのように処理しますか?

ウィキペディアによると(これは間違っている可能性があります)

Fork()システムコールが発行されると、親プロセスに対応するすべてのページのコピーが作成され、子プロセス用のOSによって別のメモリロケーションにロードされます。しかし、これは特定の場合には必要ありません。子が "exec"システムコール(Cプログラム内から実行可能ファイルを実行するために使用される)を実行する場合、またはfork()の直後に終了する場合を検討してください。親プロセスのコマンドを実行するためだけに子が必要な場合、execは、それを呼び出したプロセスのアドレス空間を実行するコマンドで置き換えるため、親プロセスのページをコピーする必要はありません。 。

このような場合、コピーオンライト(COW)と呼ばれる手法が使用されます。この手法では、フォークが発生したときに、親プロセスのページは子プロセスにコピーされません。代わりに、ページは子プロセスと親プロセスの間で共有されます。プロセス(親または子)がページを変更するときはいつでも、その特定のページだけの個別のコピーが、変更を実行したそのプロセス(親または子)に対して作成されます。このプロセスでは、今後のすべての参照で、共有されたページではなく、新しくコピーされたページが使用されます。他のプロセス(共有ページを変更しなかったプロセス)は、ページの元のコピー(現在は共有されていません)を引き続き使用します。この手法は、ページが何らかのプロセスによって書き込まれたときにコピーされるため、コピーオンライトと呼ばれます。

いずれかのプロセスがページに書き込もうとすると、ページの新しいコピーが割り当てられ、ページフォールトを生成したプロセスに割り当てられたようです。元のページは後で書き込み可能としてマークされます。

私の質問は、プロセスが共有ページに書き込もうとする前にfork()が複数回呼び出された場合はどうなりますか?

23
ssgao

特に何も起こりません。すべてのプロセスは同じページのセットを共有しており、各ページは、ページを変更するときに独自のプライベートコピーを取得します。

20
jlliagre

Fork()の動作は、* nixシステムにMMUがあるかどうかによって異なります。初期のPDP-11のような非MMUシステムでは、fork()システムコールは各子の親のメモリ。MMUベースの* nixシステムでは、カーネルはすべての非スタックページをR/Oとしてマークし、親と子の間でそれらを共有します。次に、いずれかのプロセスが任意のページに書き込むと、MMU試行をトラップし、カーネルは書き込み可能なページを割り当て、MMU page-tablesを更新して、現在書き込み可能なページを指すようにします。このコピーオンライト動作は、最初は子プロセスごとにプライベートスタックのみを割り当てて複製する必要があるため、高速化されます。

各fork()呼び出しの間に親コードを実行すると、結果の子プロセスは、親によって変更されたページによって異なります。一方、親が単に複数のfork()呼び出しを発行する場合、たとえば、ループでは、子プロセスはほぼ同じになります。ローカルループ変数が使用されている場合、それは各子のスタック内で異なります。

3
CyberFonic

システムがフォークをプリフォームするとき、通常(これは実装によって異なる場合があります)、ページを読み取り専用としてマークし、親プロセスをこれらのページのマスターとしてマークします。
これらのページに書き込もうとすると、ページフォールトが発生し、OSが引き継ぎ、ページのリスト全体または変更されたリストのみをコピーします(これも実装に依存します)。そのため、書き込みプロセスは書き込み可能になります。コピー。
同じプロセスから分岐された複数のプロセスがある場合、「マスター」プロセスがそのメモリに書き込むと、otherプロセスは同等のページをコピーします。

0
Didi Kohen