在 C 中实现多个管道
Implementing multiple pipe in C
任何人都可以告诉我为什么我以下尝试实现多个管道的代码不正确吗?我正在实施 parent-child 关系,因此不允许 parent-grandchildren 关系,即所有 children 应该 运行 并行。
当我输入命令 ls |猫 | cat,ls的内容都输出了,但是提示还是提示我输入,再输入一个字符也不停止。
我做错了吗?
int i;
int pipefd[num_of_pipe][2];
pid_t child_pid[num_of_child];
for (i = 0; i < num_of_child; i++) {
pipe(pipefd[i]);
if ((child_pid[i] = fork()) == 0) {
if (i == 0) {
close(pipefd[i][0]);
dup2(pipefd[i][1], STDOUT_FILENO);
close(pipefd[i][1]);
/* execvp something; */
} else if (i == num_of_child - 1) {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0], STDIN_FILENO);
close(pipefd[i - 1][0]);
/* execvp something */
} else {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0],0);
close(pipefd[i - 1][0]);
close(pipefd[i][0]);
dup2(pipefd[i][1],1);
close(pipefd[i][1]);
/* execvp something */
}
}
}
int k;
for (k = 0; k < num_of_child; k++) {
waitpid(child_pid[k], NULL, WUNTRACED);
printf("the %dth child returns\n", k + 1);
}
int j;
for (j = 0; j < num_of_pipe; j++) {
close(pipefd[j][0]);
close(pipefd[j][1]);
}
}
问题是您的两个 cat
进程各自在其标准输入上等待更多数据,因为并非所有管道写入端的文件描述符副本都已关闭。出现这种情况是因为父进程构建并保留了所有管道文件描述符的数组,并且仅在分叉所有子进程后才关闭它们。因此,每个子级都会继承父级迄今为止创建的 every 个打开的文件描述符,而不仅仅是供其自己使用的文件描述符。在管道写端的所有 FD 都关闭之前,在读端不会检测到 EOF。
因此,特别是,第三个子进程具有一个打开的文件描述符,用于第二个子进程正在读取的管道的写入端。它会在退出时关闭它,但它不会退出,因为第二个进程保持打开为第三个进程提供的管道的写入端。如果管道更长,问题会更糟。
您应该通过让主进程在不再需要文件描述符时立即关闭文件描述符来处理该问题,这样它们就不会被继承。使用您当前的代码结构,您可以在 fork 循环的底部执行此操作。
作为次要问题,如果您实际上依赖它们不会失败,则应始终检查函数调用的 return 值以获取错误指示器。
任何人都可以告诉我为什么我以下尝试实现多个管道的代码不正确吗?我正在实施 parent-child 关系,因此不允许 parent-grandchildren 关系,即所有 children 应该 运行 并行。 当我输入命令 ls |猫 | cat,ls的内容都输出了,但是提示还是提示我输入,再输入一个字符也不停止。 我做错了吗?
int i;
int pipefd[num_of_pipe][2];
pid_t child_pid[num_of_child];
for (i = 0; i < num_of_child; i++) {
pipe(pipefd[i]);
if ((child_pid[i] = fork()) == 0) {
if (i == 0) {
close(pipefd[i][0]);
dup2(pipefd[i][1], STDOUT_FILENO);
close(pipefd[i][1]);
/* execvp something; */
} else if (i == num_of_child - 1) {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0], STDIN_FILENO);
close(pipefd[i - 1][0]);
/* execvp something */
} else {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0],0);
close(pipefd[i - 1][0]);
close(pipefd[i][0]);
dup2(pipefd[i][1],1);
close(pipefd[i][1]);
/* execvp something */
}
}
}
int k;
for (k = 0; k < num_of_child; k++) {
waitpid(child_pid[k], NULL, WUNTRACED);
printf("the %dth child returns\n", k + 1);
}
int j;
for (j = 0; j < num_of_pipe; j++) {
close(pipefd[j][0]);
close(pipefd[j][1]);
}
}
问题是您的两个 cat
进程各自在其标准输入上等待更多数据,因为并非所有管道写入端的文件描述符副本都已关闭。出现这种情况是因为父进程构建并保留了所有管道文件描述符的数组,并且仅在分叉所有子进程后才关闭它们。因此,每个子级都会继承父级迄今为止创建的 every 个打开的文件描述符,而不仅仅是供其自己使用的文件描述符。在管道写端的所有 FD 都关闭之前,在读端不会检测到 EOF。
因此,特别是,第三个子进程具有一个打开的文件描述符,用于第二个子进程正在读取的管道的写入端。它会在退出时关闭它,但它不会退出,因为第二个进程保持打开为第三个进程提供的管道的写入端。如果管道更长,问题会更糟。
您应该通过让主进程在不再需要文件描述符时立即关闭文件描述符来处理该问题,这样它们就不会被继承。使用您当前的代码结构,您可以在 fork 循环的底部执行此操作。
作为次要问题,如果您实际上依赖它们不会失败,则应始终检查函数调用的 return 值以获取错误指示器。