プロセス作成のためのUNIXシステムコールfork()は、親プロセスをコピーして子プロセスを作成します。私の理解では、ほとんどの場合、子プロセスのメモリ空間(テキストセグメントを含む)を置き換えるためにexec()が呼び出されます。親のメモリスペースをfork()にコピーすることは常に無駄に思えました(ただし、メモリセグメントをコピーオンライトにして、ポインタだけがコピーされるようにすることで、無駄を最小限に抑えることができます)。とにかく、なぜこの複製アプローチがプロセスの作成に必要なのか知っていますか?
インターフェースを簡素化するためです。 fork
およびexec
の代わりは、Windowsの CreateProcess 関数のようなものです。 CreateProcess
にはいくつのパラメーターがあり、それらの多くはさらに多くのパラメーターを持つ構造体です。これは、新しいプロセスについて制御したいeverythingをCreateProcess
に渡す必要があるためです。実際、CreateProcess
には十分なパラメーターがないため、Microsoftは CreateProcessAsUser および CreateProcessWithLogonW を追加する必要がありました。
とともに fork/exec
モデル、これらすべてのパラメーターは必要ありません。代わりに、プロセスの特定の属性がexec
全体で保持されます。これにより、fork
を実行してから、(通常使用するのと同じ関数を使用して)必要なプロセス属性を変更し、その後exec
。 Linuxでは、fork
にはパラメータがなく、execve
には3つだけあります。実行するプログラム、それを与えるコマンドライン、およびその環境です。 (他にもexec
関数がありますが、Cライブラリが提供するexecve
のラッパーであり、一般的な使用例を簡略化しています。)
別の現在のディレクトリでプロセスを開始する場合:fork
、chdir
、exec
。
Stdin/stdoutをリダイレクトする場合:fork
、ファイルを閉じる/開く、exec
。
ユーザーを切り替える場合:fork
、setuid
、exec
。
これらすべては必要に応じて組み合わせることができます。誰かが新しい種類のプロセス属性を思いついた場合、fork
とexec
を変更する必要はありません。
ラースクが述べたように、最近のほとんどのUnixはコピーオンライトを使用しているため、fork
は大きなオーバーヘッドを伴いません。
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
です。コピーオンライトを使用しない実装では、結果のプロセスは元のプロセスとメモリ空間を共有します(そのため、未定義の動作)。コピーオンライトの実装は高速であるため、コピーオンライトの実装では、vfork
はfork()
と同じであることが許可されます。
新しいプロセスを直接作成できるオプションの_posix_spawn
_関数(および_posix_spawnp
_関数)もあります。 (fork
とexec
を使用したライブラリ呼び出しでそれらを実装することも許可されており、実装例が提供されています。)