web-dev-qa-db-ja.com

デフォルトのプロセス作成メカニズムがフォークするのはなぜですか?

プロセス作成のためのUNIXシステムコールfork()は、親プロセスをコピーして子プロセスを作成します。私の理解では、ほとんどの場合、子プロセスのメモリ空間(テキストセグメントを含む)を置き換えるためにexec()が呼び出されます。親のメモリスペースをfork()にコピーすることは常に無駄に思えました(ただし、メモリセグメントをコピーオンライトにして、ポインタだけがコピーされるようにすることで、無駄を最小限に抑えることができます)。とにかく、なぜこの複製アプローチがプロセスの作成に必要なのか知っていますか?

47
Ellen Spertus

インターフェースを簡素化するためです。 forkおよびexecの代わりは、Windowsの CreateProcess 関数のようなものです。 CreateProcessにはいくつのパラメーターがあり、それらの多くはさらに多くのパラメーターを持つ構造体です。これは、新しいプロセスについて制御したいeverythingCreateProcessに渡す必要があるためです。実際、CreateProcessには十分なパラメーターがないため、Microsoftは CreateProcessAsUser および CreateProcessWithLogonW を追加する必要がありました。

とともに fork/execモデル、これらすべてのパラメーターは必要ありません。代わりに、プロセスの特定の属性がexec全体で保持されます。これにより、forkを実行してから、(通常使用するのと同じ関数を使用して)必要なプロセス属性を変更し、その後exec。 Linuxでは、forkにはパラメータがなく、execveには3つだけあります。実行するプログラム、それを与えるコマンドライン、およびその環境です。 (他にもexec関数がありますが、Cライブラリが提供するexecveのラッパーであり、一般的な使用例を簡略化しています。)

別の現在のディレクトリでプロセスを開始する場合:forkchdirexec

Stdin/stdoutをリダイレクトする場合:fork、ファイルを閉じる/開く、exec

ユーザーを切り替える場合:forksetuidexec

これらすべては必要に応じて組み合わせることができます。誰かが新しい種類のプロセス属性を思いついた場合、forkexecを変更する必要はありません。

ラースクが述べたように、最近のほとんどのUnixはコピーオンライトを使用しているため、forkは大きなオーバーヘッドを伴いません。

60
cjm

Cjmの答えに加えて、Single Unix Specificationはvfork()という名前の関数を定義しています。その関数はforkのように機能しますが、execファミリ関数の呼び出しや_exit()の呼び出し以外の処理を行う場合、forkされたプロセスは未定義の動作をします。

したがって、定義された動作で使用できるのはほとんど次のとおりです。

_pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}
_

では、vforkは何をするのでしょうか?安価なforkです。コピーオンライトを使用しない実装では、結果のプロセスは元のプロセスとメモリ空間を共有します(そのため、未定義の動作)。コピーオンライトの実装は高速であるため、コピーオンライトの実装では、vforkfork()と同じであることが許可されます。

新しいプロセスを直接作成できるオプションの_posix_spawn_関数(および_posix_spawnp_関数)もあります。 (forkexecを使用したライブラリ呼び出しでそれらを実装することも許可されており、実装例が提供されています。)

5
Kevin Cathcart