経験則: dup()
orを使用dup2()
してパイプの一方の端を標準入力または標準出力にマップする場合close()
は、パイプ自体の両方の端をマップする必要があります。あなたはそうしていません。あなたの待機はプログラムが終了するのを待っていますが、パイプに書き込むことができるパイプが開いているプロセスがまだあるため、プログラムは終了しません。また、パイプを作成したプロセスは、それ自体はパイプを使用していないため (子プロセスがパイプを使用しているため)、パイプの両端を閉じる必要があります。C MiniShell — パイプラインの追加も参照してください。
また、最初の子が終了するのを待ってから 2 番目の子を起動するべきではありません (したがって、このpid2 = wait(&status2);
行は悪い考えです)。パイプの容量はかなり小さいです。転送するデータの合計が大きすぎる場合、書き込み中の子は読み取り中の子が読み取るのを待ってブロックする可能性がありますが、書き込み中の子が終了するのを待っているため、読み取り中の子はまだ開始されていません (また、処理に長い時間がかかります)。このデッドロックは自動的に解決されます)。wait()
パイプラインの 2 番目の部分が実行され、パイプラインの最初の部分からのデータが処理されるため、呼び出しなしで出力が表示されますが、シェルからさらにデータが来るのをまだ待っています。
これらのヒントを考慮に入れると、次のようになる可能性があります。
pipe(mypipe);
pid1 = fork();
if (pid1 == 0)
{
pid2 = fork();
if (pid2 == 0)
{
close(0);
dup(mypipe[0]);
close(mypipe[1]);
close(mypipe[0]);
execv(foundnode2->path_dir, arv2);
fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
exit(1);
}
close(1);
dup(mypipe[1]);
close(mypipe[0]);
close(mypipe[1]);
execv(foundnode1->path_dir, arv1);
fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
exit(1);
}
close(mypipe[0]);
close(mypipe[1]);
pid1 = wait(&status1);
コマンドが失敗すると、エラーが標準エラーに報告されることに注意してくださいexecv()
。また、0 の終了ステータスは成功のために予約する必要があります。EXIT_FAILURE
1 は便利なエラー終了ステータスです。またはfromを使用できます<stdlib.h>
。
多くのエラー チェックがまだ省略されています。fork()
操作が失敗する可能性があります。pipe()
失敗する可能性があります。結果の 1 つは、2 番目fork()
が失敗した場合でも、2 番目の子 ( で識別される) を起動することですfoundnode1->path_dir
。
また、パイプの作成を最初の子プロセスに移動することで、少し手間を省くことができることに注意してください (親はパイプを閉じる必要はありません (実際にはできません))。
int pid1 = fork();
if (pid1 == 0)
{
int mypipe[2];
pipe(mypipe);
int pid2 = fork();
if (pid2 == 0)
{
close(0);
dup(mypipe[0]);
close(mypipe[1]);
close(mypipe[0]);
execv(foundnode2->path_dir, arv2);
fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
exit(1);
}
close(1);
dup(mypipe[1]);
close(mypipe[0]);
close(mypipe[1]);
execv(foundnode1->path_dir, arv1);
fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
exit(1);
}
pid1 = wait(&status1);