Solaris 11.3 で実行される次のコードを検討してください。
int main(void) {
pid_t pid = fork();
if (pid > 0) {
printf("[%ld]: Writing from parent process\n", getpid());
}
if (pid == 0) {
execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
perror("exec failed");
exit(1);
}
}
実行するたびに、「write from parent」行が常に最後に出力されます。私の学校の課題で子プロセスが完了した後にのみ行を印刷するためにwait(2)を使用しなかった場合、この結果は驚くことはありません。なぜこれが起こり、この問題を解決するためにwait(2)またはwaitpid(2)を安全に使用できるように、子プロセスがcatを実行する前に(または順序が少なくとも定義されていない場合)、この行が印刷されるようにします。するにはどうすればよいですか?
答え1
@AndrewHenleが述べたように、特定の順序でプロセスをスケジュールするためにシステムに頼ることは安全ではなく不合理です。あなたの場合のようにスケジュールが一貫しているように見えても、オペレーティングシステムの実装者がスケジューラの動作を変更するのを防ぐ方法はありません。
プロセス/スレッド間の作業順序が関係する場合は、ある種の通信が必要です。
あなたのシナリオでは、簡単なブロッキング読み取りがアクションを実行します。フォークの前にパイプを作成します。その後、親はメッセージを印刷した後にのみ親のパイプに書き込みます。同時に、パイプからデータを読み取ろうとする子プロセスは、親プロセスが書き込むまで実行をブロックします。
各プロセスでエラー処理と廃止されたパイプファイル記述子(通常は分岐後に明示的に閉じる)を無視します。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
char buf[1];
int pipe_fds[2];
pipe(pipe_fds);
pid_t pid = fork();
if (pid > 0) {
printf("[%ld]: Writing from parent process\n", getpid());
write(pipe_fds[1], "_", 1);
wait(NULL);
}
if (pid == 0) {
read (pipe_fds[0], buf, 1);
execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
perror("exec failed");
exit(1);
}
端末で実行している場合は、子の出力とシェルプロンプトがインターリーブされないように、親で待機を使用する必要があります。
答え2
カーネルの観点から考えてみてください。サブプロセスを設定してさまざまなキャッシュを破壊するだけであり、次にそのサブプロセスを実行すると、新しいキャッシュコンテンツの一部を再利用できます。同時に、親プロセスを別のCPUに予約できます。
答え3
原則として、両方のプロセスを並列に実行できますが、親プロセスはすでにCPUでアクティブになっており、子プロセスはexec
出力を生成する前に最初に新しいプロセスを作成する必要があります。親プロセスは、子プロセスがそのプロセスを置き換える前に完了する可能性が高いです。