我不認爲信號處理是相關的。有關的是確保管道正確關閉。如果有一個寫入結束的進程打開,進程將不會在管道的讀取端獲得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'。此外,你錯過了一個關鍵的頭文件包含。 –
至於你的問題,你需要*兩個*管道。您不能重複使用現有的管道。 –