【发布时间】:2014-02-15 11:09:15
【问题描述】:
我对昨天提出的一个现有问题感到困惑:
Recursive piping in Unix again。
我重新发布有问题的代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void pipeline( char * ar[], int pos, int in_fd);
void error_exit(const char*);
static int child = 0; /* whether it is a child process relative to main() */
int main(int argc, char * argv[]) {
if(argc < 2){
printf("Usage: %s option (option) ...\n", argv[0]);
exit(1);
}
pipeline(argv, 1, STDIN_FILENO);
return 0;
}
void error_exit(const char *kom){
perror(kom);
(child ? _exit : exit)(EXIT_FAILURE);
}
void pipeline(char *ar[], int pos, int in_fd){
if(ar[pos+1] == NULL){ /*last command */
if(in_fd != STDIN_FILENO){
if(dup2(in_fd, STDIN_FILENO) != -1)
close(in_fd); /*successfully redirected*/
else error_exit("dup2");
}
execlp(ar[pos], ar[pos], NULL);
error_exit("execlp last");
}
else{
int fd[2];
pid_t childpid;
if ((pipe(fd) == -1) || ((childpid = fork()) == -1)) {
error_exit("Failed to setup pipeline");
}
if (childpid == 0){ /* child executes current command */
child = 1;
close(fd[0]);
if (dup2(in_fd, STDIN_FILENO) == -1) /*read from in_fd */
perror("Failed to redirect stdin");
if (dup2(fd[1], STDOUT_FILENO) == -1) /*write to fd[1]*/
perror("Failed to redirect stdout");
else if ((close(fd[1]) == -1) || (close(in_fd) == - 1))
perror("Failed to close extra pipe descriptors");
else {
execlp(ar[pos], ar[pos], NULL);
error_exit("Failed to execlp");
}
}
close(fd[1]); /* parent executes the rest of commands */
close(in_fd);
pipeline(ar, pos+1, fd[0]);
}
}
发生的错误是:
Example:
./prog ls uniq sort head
gives:
sort: stat failed: -: Bad file descriptor
建议的解决方案是,“不要在子进程中关闭文件描述符 fd[1] 和 in_fd,因为它们已经在父进程中关闭。”
我的困惑:(对不起,我是 Linux 新手)
根据我的《开始 Linux 编程》一书,当我们 fork() 一个进程时,文件描述符也会被复制。因此父母和孩子应该有不同的文件描述符。这与答案相矛盾。
我的尝试:
我尝试自己运行这段代码,我发现问题只有在我关闭两个进程(父进程和子进程)中的“in_fd”文件描述符时才会出现。它不依赖于 fd[1]。
另外,有趣的是,如果我尝试./prog ls sort head,它可以正常工作,但是当我尝试./prog ls sort head uniq 时,它会在head 上出现读取错误。
我的想法:
in_fd 文件描述符只是此函数的输入 int 变量。似乎即使在 fork 之后,也只剩下一个文件描述符被父子共享。但我无法理解。
【问题讨论】:
-
请看我的回答,如果我无法澄清任何事情,请在此处发表评论。
-
dup2( in_fd, STDIN_FILENO)在 in_fd == STDIN_FILENO 时有问题。您在代码中的某个地方发现了这个问题,但在另一个地方忽略了它。 -
@WilliamPursell 你能解释一下如果 in_fd 最初是 STDIN_FILENO 会导致什么问题吗?谢谢!
-
@user3154219 我错了。如果两个文件描述符相同,
dup3将失败,但对于dup2:“如果 fildes2 已经是一个有效的打开文件描述符,则应首先关闭它,除非 fildes 等于 fildes2 在这种情况下 dup2() 应返回 fildes2 而不关闭它”,所以这应该不是问题。