int main()
{
int p[2];
int p1[2];
pipe(p);
pipe(p1);
int pid,status;
char buff[10000];
pid = fork();
if(pid == 0)
{
close(p[0]);
dup2(p[1],1);
close(p[1]);
char *argv[] = {"ls","-l",NULL};
execv("/bin/ls",argv);
}
else
{
wait(&status);
pid =fork();
if (pid ==0)
{
close(p[1]);
dup2(p[0],0);
close(p[0]);
close(p1[0]);
dup2(p1[1],1);
close(p1[1]);
char *argv[] = {"uniq",NULL};
execv("/bin/uniq",argv);
}
else
{
wait(&status);
close(p1[1]);
dup2(p1[0],0);
close(p1[0]);
char *argv[] = {"grep","^d",NULL};
execv("/bin/grep",argv);
}
}
}
为什么读取是在子进程中阻塞(uniq进程),即使我已正确关闭了端点(假设我已经关闭)。尝试过strace并且持续打3到4小时。我想知道它为什么阻止......任何帮助都会有所帮助:)
答案 0 :(得分:1)
问题是您没有关闭所有未使用的管道文件描述符。例如,在您exec("/bin/grep", argv)
的最后一个分支中,您关闭了p1[1]
和dup2()
p1[0]
,但您并未关闭{{1} }或p[0]
。因此,当p[1]
写完ls
时,该管道保持打开状态,因为您仍然有悬空引用它。
您还没有检查任何系统调用是否存在错误,您应该这样做。
以下是修订版(略有修改,因为uniq
和grep
位于我系统的不同位置):
uniq
并输出:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int p1to2[2];
int p2to3[2];
if ( pipe(p1to2) == -1 || pipe(p2to3) == -1 ) {
perror("error calling pipe()");
return EXIT_FAILURE;
}
pid_t pid;
if ( (pid = fork()) == -1 ) {
perror("error calling first fork()");
return EXIT_FAILURE;
}
else if (pid == 0) {
if ( close(p1to2[0]) == -1 ) {
perror("error calling close() on p1to2[0]");
return EXIT_FAILURE;
}
if ( p1to2[1] != STDOUT_FILENO ) {
if ( dup2(p1to2[1], STDOUT_FILENO) == -1 ) {
perror("error calling dup2() on p1to2[1]");
return EXIT_FAILURE;
}
if ( close(p1to2[1]) == -1 ) {
perror("error calling close() on p1to2[1]");
return EXIT_FAILURE;
}
}
if ( close(p2to3[0]) == -1 || close(p2to3[1]) == -1 ) {
perror("error calling close() on p2to3");
return EXIT_FAILURE;
}
char *argv[] = {"ls", "-l", NULL};
if ( execv("/bin/ls", argv) == -1 ) {
perror("couldn't execute /bin/ls");
return EXIT_FAILURE;
}
} else {
if ( (pid = fork()) == -1 ) {
perror("error calling second fork()");
return EXIT_FAILURE;
}
else if ( pid == 0 ) {
if ( close(p1to2[1]) == -1 ) {
perror("error calling close() on p1to2[1]");
return EXIT_FAILURE;
}
if ( p1to2[0] != STDIN_FILENO ) {
if ( dup2(p1to2[0], STDIN_FILENO) == -1 ) {
perror("error calling dup2() on p1to2[0]");
return EXIT_FAILURE;
}
if ( close(p1to2[0]) == -1 ) {
perror("error calling close() on p1to2[0]");
return EXIT_FAILURE;
}
}
if ( close(p2to3[0]) == -1 ) {
perror("error calling close() on p2to3[0]");
return EXIT_FAILURE;
}
if ( p2to3[1] != STDOUT_FILENO ) {
if ( dup2(p2to3[1], STDOUT_FILENO) == -1 ) {
perror("error calling dup2() on p2to3[1]");
return EXIT_FAILURE;
}
if ( close(p2to3[1]) == -1 ) {
perror("error calling close() on p2to3[1]");
return EXIT_FAILURE;
}
}
char *argv[] = {"uniq", NULL};
if ( execv("/usr/bin/uniq", argv) == -1 ) {
perror("couldn't execute /usr/bin/uniq");
return EXIT_FAILURE;
}
} else {
if ( close(p1to2[0]) == -1 || close(p1to2[1]) == -1 ) {
perror("error calling close() on p1to2");
return EXIT_FAILURE;
}
if ( close(p2to3[1]) == -1 ){
perror("error calling close() on p2to3[1]");
return EXIT_FAILURE;
}
if ( p2to3[0] != STDIN_FILENO ) {
if ( dup2(p2to3[0], STDIN_FILENO) == -1 ) {
perror("error calling dup2() on p2to3[0]");
return EXIT_FAILURE;
}
if ( close(p2to3[0]) == -1 ) {
perror("error calling close() on p2to3[0]");
return EXIT_FAILURE;
}
}
char *argv[] = {"grep", "pipes", NULL};
if ( execv("/usr/bin/grep", argv) == -1 ) {
perror("couldn't execute /usr/bin/grep");
return EXIT_FAILURE;
}
}
}
}
顺便提一下,当您有多个管道paul@horus:~/src/sandbox$ ./pipes
-rwxr-xr-x 1 paul staff 8812 Oct 25 12:21 pipes
-rw-r--r-- 1 paul staff 3817 Oct 25 12:21 pipes.c
-rw------- 1 paul staff 660 Oct 25 11:03 pipes.c.BAK
paul@horus:~/src/sandbox$
,close()
以及dup2()
和p
等变量时,很容易感到困惑,特别是当您添加需要的错误检查时。这是一个很好的例子,将程序组合成函数可以极大地帮助,并避免因为很难弄清楚正在发生什么而引入错误。
以下是建议的构成,我建议p1
功能在此处更容易理解,推理和排除故障:
main()