Вы закрываете недостаточно файловых дескрипторов.
/* Semi-working code */
int main()
{
int pipeA[2];
int pipeB[2];
pipe(pipeA);
pipe(pipeB);
int pidA,pidB,pidC;
if (pidA = fork())
{
close(pipeB[0]); // "ls" is not going to use the second pipe
close(pipeB[1]); // Ditto
close(pipeA[0]);
dup2(pipeA[1], 1);
close(pipeA[1]);
execlp("ls", "ls", "/bin", (char *)NULL);
fprintf(stderr, "error executing 'ls'\n");
exit(1);
}
if (pidB = fork())
{
close(pipeA[1]);
dup2(pipeA[0],0);
close(pipeA[0]);
close(pipeB[0]);
dup2(pipeB[1],1);
close(pipeB[1]);
execlp("grep", "grep", "grep", (char *)NULL);
fprintf(stderr, "error execing 'grep grep'\n");
exit(1);
}
if (pidC = fork())
{
close(pipeA[0]); // The second grep is not going to use the first pipe
close(pipeA[1]); // Ditto
close(pipeB[1]);
dup2(pipeB[0],0);
close(pipeB[0]);
execlp("grep", "grep", "b", (char *)NULL);
fprintf(stderr, "error execing 'grep b'\n");
exit(1);
}
close(pipeA[0]); // The parent process is not using the pipes at all
close(pipeA[1]);
close(pipeB[0]);
close(pipeB[1]);
while (pidA != wait(0))
;
return 0;
}
Поскольку вы не закрыли pipeA
во втором grep
, вы получите первый grep
, ожидающий ввода из канала, второй grep
по-прежнему открыт, даже если процесс не запишет к этому. Из-за этого первый grep
не заканчивается, поэтому второй также не заканчивается - даже если ls
завершается. Эти комментарии будут применяться, даже если родительский процесс закрыл свои копии каналов - как исправленный код.
Обратите внимание, как вы закрываете все 4 дескриптора, возвращаемых двумя вызовами pipe()
в каждом из четырех процессов - три дочерних и родительский процесс.
Это оставляет одну остаточную проблему - иерархия процессов перевернута из-за вашего обычного использования if (pidA = fork())
. У вас есть дочерний процесс, ожидающий своих родителей. Вам необходимо использовать:
if ((pidA = fork()) == 0)
{
/* Be childish */
}
Аналогично для каждого из двух других процессов. Вы также должны проверить pipe()
вызовы и fork()
вызовы на отказ, просто чтобы быть уверенным.
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <stdlib.h>
static void err_exit(const char *format, ...);
/* Working code */
int main(void)
{
int pipeA[2];
int pipeB[2];
if (pipe(pipeA) != 0 || pipe(pipeB) != 0)
err_exit("Failed to create a pipe\n");
int pidA,pidB,pidC;
if ((pidA = fork()) < 0)
err_exit("Failed to fork (A)\n");
else if (pidA == 0)
{
close(pipeB[0]); // "ls" is not going to use the second pipe
close(pipeB[1]); // Ditto
close(pipeA[0]);
dup2(pipeA[1], 1);
close(pipeA[1]);
execlp("ls", "ls", "/bin", (char *)NULL);
err_exit("error executing 'ls'\n");
}
if ((pidB = fork()) < 0)
err_exit("failed to fork (B)\n");
else if (pidB == 0)
{
close(pipeA[1]);
dup2(pipeA[0],0);
close(pipeA[0]);
close(pipeB[0]);
dup2(pipeB[1],1);
close(pipeB[1]);
execlp("grep", "grep", "grep", (char *)NULL);
err_exit("error execing 'grep grep'\n");
}
if ((pidC = fork()) < 0)
err_exit("failed to fork (C)\n");
else if (pidC == 0)
{
close(pipeA[0]); // The second grep is not going to use the first pipe
close(pipeA[1]); // Ditto
close(pipeB[1]);
dup2(pipeB[0],0);
close(pipeB[0]);
execlp("grep", "grep", "b", (char *)NULL);
err_exit("error execing 'grep b'\n");
}
close(pipeA[0]); // The parent process is not using the pipes at all
close(pipeA[1]);
close(pipeB[0]);
close(pipeB[1]);
while (wait(0) != -1)
;
printf("Continuing here...\n");
sleep(3);
printf("That's enough of that!\n");
return 0;
}
static void err_exit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
}
Эта программа работает нормально в Mac OS X 10.7.3, если ее использовать /usr/bin
вместо /bin
. В нем перечислены три файла, а затем генерируется сообщение «Продолжение здесь»:
bzegrep
bzfgrep
bzgrep
Continuing here...
That's enough of that!