我对昨天提出的现有问题感到困惑:
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新手)
根据我的书“Beginning Linux Programming”,当我们fork()一个进程时,文件描述符也会被复制。因此父母和孩子应该有不同的文件描述符。这与答案相矛盾。
我的尝试:
我试图自己运行这个代码,我发现只有在两个进程(父进程和子进程)中关闭“in_fd”文件描述符时才会出现问题。它不依赖于fd [1]
另外,有趣的是,如果我尝试./prog ls sort head
它可以正常工作,但是当我尝试./prog ls sort head uniq
时,它会在head
上发出读取错误。
我的想法:
in_fd
文件描述符只是此函数的输入int变量。似乎即使在fork之后,只有一个文件描述符仍然由父和子共享。但我无法理解如何。
答案 0 :(得分:0)
当我们fork()一个进程时,文件描述符也是 复制。因此父母和孩子应该有不同的文件 描述符
文件描述符是一个简单的integer
。因此,当它被复制时,它具有相同的值,因此它们指向同一个文件。
因此,您可以在父级中打开文件,并从子级访问它。唯一可能出现的问题是如果从父级和子级访问文件,在这种情况下,不能保证它将从哪个文件位置访问。为避免这种情况,建议关闭子进程中的fd并重新打开。
正如你所说的那样,我对上述问题做了同样的事情,并发现第4个命令总是发生这种情况。此外,dup2()
关闭它正在复制的文件。在问题中,fd[1]
和in_fd
被复制到了孩子的stdin
和stdout
。当时fd[1]
和in_fd
已关闭。没有必要再次关闭它们。
关闭已经关闭的描述符将导致错误。
由于您不知道父或子是否将首先执行,如果您从子节点关闭一个文件,并再次从父节点关闭,可能会导致问题,并且此类行为是不可预测的。