我不认为信号处理是相关的。有关的是确保管道正确关闭。如果有一个写入结束的进程打开,进程将不会在管道的读取端获得EOF。这包括当前的过程;如果一个进程同时打开了管道的读写端,它将永远不会在管道的读端读取EOF,因为理论上有一个进程可以写入该进程。这样的过程因此永久地挂在管道上的read()
中。
这个版本的代码为我工作得很好:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int pdesk[2];
int pipedesk[2];
int pid;
if (pipe(pipedesk) == -1 || pipe(pdesk) == -1)
{
perror("Pipe");
exit(1);
}
//fprintf(stderr, "PID %d: controller\n", (int)getpid());
switch (pid = fork())
{
case -1:
perror("Creating process");
exit(1);
case 0:
//fprintf(stderr, "PID %d: will be 'ls'\n", (int)getpid());
dup2(pdesk[1], STDOUT_FILENO);
close(pdesk[0]); // JL
close(pdesk[1]);
close(pipedesk[0]); // JL
close(pipedesk[1]); // JL
execlp("ls", "ls", "-al", (char *)NULL);
perror("ls");
exit(1);
default:
//fprintf(stderr, "PID %d: ls process PID = %d\n", (int)getpid(), pid);
if ((pid = fork()) == 0)
{
//fprintf(stderr, "PID %d: about to fork 'tr'\n", (int)getpid());
if ((pid = fork()) == 0)
{
//fprintf(stderr, "PID %d: will be 'tr'\n", (int)getpid());
dup2(pdesk[0], STDIN_FILENO);
close(pdesk[0]);
close(pdesk[1]); // JL
dup2(pipedesk[1], STDOUT_FILENO);
close(pipedesk[0]); // JL
close(pipedesk[1]);
execlp("tr", "tr", "a-z", "A-Z", (char *)NULL);
perror("tr");
exit(1);
}
//fprintf(stderr, "PID %d: about to exec 'grep'\n", (int)getpid());
dup2(pipedesk[0], STDIN_FILENO);
close(pdesk[0]); // JL
close(pdesk[1]); // JL
close(pipedesk[0]);
close(pipedesk[1]); // JL
int desk = open("testing", O_WRONLY | O_CREAT, 0644);
if (desk == -1)
{
perror("opening file");
exit(1);
}
dup2(desk, STDOUT_FILENO);
if (close(desk) == -1)
{
perror("closing file");
exit(1);
}
execlp("grep", "grep", "X", (char *)NULL);
perror("grep");
exit(1);
}
//fprintf(stderr, "PID %d: closing pipes\n", (int)getpid());
close(pdesk[0]); // JL
close(pdesk[1]); // JL
close(pipedesk[0]); // JL
close(pipedesk[1]); // JL
break;
}
int status;
int corpse;
while ((corpse = wait(&status)) != -1)
fprintf(stderr, "PID %d: child %d died 0x%.4X\n", (int)getpid(), corpse, status);
return 0;
}
注意所有的行标// JL
这是关闭操作。虽然你可以在没有少数人的情况下离开(例如,对于第一个孩子来说可能是'可选的'),但你应该按照惯例关闭所有你不使用的管道。请注意,特别是关于原始父进程(最后四个)的关闭 - 这些都很重要。
未关闭足够多的管道描述符是使用多个管道时最常见的错误之一。通常,如果使用dup2()
(或dup()
)将管道描述符复制到标准输入或输出,则应关闭两个两端的原始管道。如果你的进程根本没有使用管道描述符,你应该关闭它们。从程序
输出样本:
$ ./pp61
PID 35665: child 35666 died 0x0000
PID 35665: child 35667 died 0x0000
$
testing
文件的内容示例:
DRWXR-XR-X 44 JLEFFLER STAFF 1496 NOV 23 17:28 .
DRWXR-XR-X 137 JLEFFLER STAFF 4658 NOV 23 17:28 ..
DRWXR-XR-X 18 JLEFFLER STAFF 612 OCT 23 20:00 .GIT
DR-XR-XR-X 4 JLEFFLER STAFF 136 AUG 14 23:27 SAFE
DRWXR-XR-X 35 JLEFFLER STAFF 1190 NOV 23 09:19 UNTRACKED
-RW-R--R-- 1 JLEFFLER STAFF 81 NOV 20 20:53 ANIMALS.TXT
DRWXR-XR-X 3 JLEFFLER STAFF 102 SEP 12 00:03 DOC
DRWXR-XR-X 8 JLEFFLER STAFF 272 NOV 10 20:58 ETC
DRWXR-XR-X 17 JLEFFLER STAFF 578 JUL 15 19:06 INC
-RW-R--R-- 1 JLEFFLER STAFF 1217 NOV 21 21:26 IX37.SQL
DRWXR-XR-X 5 JLEFFLER STAFF 170 JUL 9 23:47 LIB
-RWXR-XR-X 1 JLEFFLER STAFF 9052 NOV 19 13:01 LL73
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 6 15:40 LL73.DSYM
-RWXR-XR-X 1 JLEFFLER STAFF 8896 NOV 6 10:38 LL83
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 6 10:10 LL83.DSYM
-RW-R--R-- 1 JLEFFLER STAFF 108 NOV 20 20:53 NEWANIMAL.TXT
-RWXR-XR-X 1 JLEFFLER STAFF 9124 NOV 20 20:38 PD43
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 20 20:38 PD43.DSYM
-RWXR-XR-X 1 JLEFFLER STAFF 9148 NOV 23 17:28 PP61
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 14:11 PP61.DSYM
-RWXR-XR-X 1 JLEFFLER STAFF 9016 NOV 23 11:07 RS19
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 10:03 RS19.DSYM
DRWXR-XR-X 146 JLEFFLER STAFF 4964 OCT 9 17:06 SRC
-RWXR-XR-X 1 JLEFFLER STAFF 8760 NOV 23 13:12 STP83
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 13:04 STP83.DSYM
DRWXR-XR-X 6 JLEFFLER STAFF 204 NOV 6 21:52 TMP
-RWXR-XR-X 1 JLEFFLER STAFF 8808 NOV 23 10:38 TR37
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 10:38 TR37.DSYM
-RWXR-XR-X 1 JLEFFLER STAFF 26772 NOV 21 20:18 XY73
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 21 20:18 XY73.DSYM
-RW-R--R-- 1 JLEFFLER STAFF 467 NOV 21 20:18 XY73.L
不起作用??? –
请避免使用[*幻数*](https://en.wikipedia.org/wiki/Magic_number_(编程))。改为使用预定义的宏,例如'STDIN_FILENO'和'STDOUT_FILENO'。此外,你错过了一个关键的头文件包含。 –
至于你的问题,你需要*两个*管道。您不能重复使用现有的管道。 –