質問
以下のこのコードは、ls -l | wc -l。 コードでは、親でclose(p [1])をコメントすると、プログラムはハングし、入力を待ちます。なぜそうですか?子はlsの出力をp1に書き込み、親はその出力をp0から取得する必要があります。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
main ()
{
int i;
int p[2];
pid_t ret;
pipe (p);
ret = fork ();
if (ret == 0)
{
close (1);
dup (p[1]);
close (p[0]);
execlp ("ls", "ls", "-l", (char *) 0);
}
if (ret > 0)
{
close (0);
dup (p[0]);
//Doubt, Commenting the line below does not work WHy?
close (p[1]);
wait (NULL);
execlp ("wc", "wc", "-l", (char *) 0);
}
}
解決
pipe
+ fork
は4つのファイル記述子を作成し、2つは入力です
フォークの前に、1つの入力と1つの出力を持つ単一のパイプがあります。
フォークの後に、2つの入力と2つの出力を持つ単一のパイプがあります。
パイプに2つの入力(procが書き込む)と2つの出力(procが読み取る)がある場合、他の入力を閉じる必要があります。そうしないと、リーダーにも閉じられないパイプ入力があります。
あなたの場合、親はリーダーであり、パイプの出力端に加えて、理論的にはスタッフができるパイプの開いたもう一方の端、または入力端を持っていますに書き込まれます。その結果、パイプがeofを送信することはありません。これは、子が終了しても、親の未使用fdによりパイプがまだ開いているためです。
したがって、親はデッドロックし、自分自身への書き込みを永久に待機します。
他のヒント
「 dup(p [1])
」は、同じファイルを指す2つのファイル記述子があることを意味します。 p [1]
は閉じません。明示的に行う必要があります。同様に、 ' dup(p [0])
'を使用します。パイプから開いている書き込みファイル記述子がない場合、パイプから読み取るファイル記述子はゼロバイト(EOF)のみを返すことに注意してください。最後の書き込み記述子が閉じられるまで、読み取りプロセスは無期限にハングします。書き込み終了を dup()
する場合、書き込み終了までに2つの開いているファイル記述子があり、読み取りプロセスがEOFを取得する前に両方を閉じる必要があります。
また、コードで wait()
を呼び出す必要もありません。 ls
リストがパイプが保持できるサイズよりも大きい場合、プロセスはデッドロックし、子は ls
の完了を待機し、 ls
は書き込まれたデータの読み取りを続行する子。
冗長な素材が取り除かれると、作業コードは次のようになります。
#include <unistd.h>
int main(void)
{
int p[2];
pid_t ret;
pipe(p);
ret = fork();
if (ret == 0)
{
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
execlp("ls", "ls", "-l", (char *) 0);
}
else if (ret > 0)
{
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
execlp("wc", "wc", "-l", (char *) 0);
}
return(-1);
}
Solaris 10では、警告なしでコンパイルされます。
Black JL: gcc -Wall -Werror -Wmissing-prototypes -Wstrict-prototypes -o x x.c
Black JL: ./x
77
Black JL:
子が p [1]
を閉じない場合、そのFDは親と子の2つのプロセスで開かれます。親は最終的に閉じますが、子は閉じません。したがって、FDは開いたままになります。したがって、そのFDの読者(この場合は子)は、それ以上の書き込みが行われる場合に備えて、いつまでも待機します。 p>