fork(2) を呼び出すと、呼び出しプロセスを正確にコピーして新しいプロセスを生成します。この新しいプロセスを子プロセスといい、呼び出し側を親プロセスといいます。子プロセスは、新しい固有のプロセス ID を取得します。fork(2) は、正常終了すると子プロセスに 0 を戻し、親プロセスに子のプロセス ID を戻します。戻り値によって、それが親プロセスか子プロセスかがわかります。
fork(2) 関数または exec(2) 関数によって生成される新しいプロセスは、3 つの標準ファイル stdin、stdout、stderr を含めた開いているすべてのファイル記述子を親から継承します。親プロセスが、子プロセスの出力よりも先に表示しなければならない出力をバッファリングしている場合、fork(2) の前にバッファをフラッシュしなければなりません。
次のコード例は、fork(2) および後続のアクションを呼び出します。
pid_t pid; pid = fork; switch (pid) { case -1: /* fork が失敗した */ perror ("fork"); exit (1); case 0: /* 新しい子プロセスで */ printf ("In child, my pid is: %d¥n", getpid(); ); do_child_stuff(); exit (0); default: /* 親では、pid は子の PID を持つ */ printf ("In parent, my pid is %d, my child is %d¥n", getpid(), pid); break; } /* 親プロセスコード */ ... |
また、親プロセスと子プロセスの両方がストリームから入力を読み込む場合、一方のプロセスが読み込んだ情報を、もう一方のプロセスは読み込むことができません。これは、入力バッファから、あるプロセスに情報が送られると、読み込みポインタが移動してしまうからです。
従来は、fork(2) と exec(2) を使用して別の実行プロセスを起動し、新しいプロセスが終了するまで待つという方法が使われていました。実際には、第 2 のプロセスはサブルーチンを呼び出すために作成されます。サブルーチンを一時的にメモリに常駐させるには、「実行時リンク」で説明するように、dlopen(3DL)、dlsym(3DL)、dlclose(3DL) を使用する方が効率的です。
exec(2) は、execl(2)、execv(2)、execle(2)、execve(2)、execvp(2) を含む関数ファミリ名です。これらの関数はいずれも、呼び出しプロセスを新しいプロセスで置き換えますが、引数のまとめ方と表し方が異なります。たとえば、execl(2) は次のように使用できます。
execl("/usr/bin/prog2", "prog2", progarg1, progarg2, (char (*)0)); |
exec1(2) 引数リストは、次のとおりです。
/usr/bin/prog2 |
新しいプロセスファイルのパス名 |
prog2 |
新しいプロセスが argv[0]に取り込む名前 |
progarg1 progarg2 |
prog2 への char (*) 型の引数 |
(char (*)0) |
引数の終わりを示す NULL の char ポインタ |
exec(2) が正常に実行されるといかなる時でも、復帰はありません。新しいプロセスが exec(2) を呼び出したプロセスを上書きしてしまうためです。新しいプロセスは、古いプロセスのプロセス ID やその他の属性を引き継ぎます。exec(2) の呼び出しが失敗すると、制御は呼び出しプログラムに戻され、戻り値 -1 が返されます。errno をチェックすれば、失敗した理由がわかります。