我一直在尝试编写一个非常简单的程序,其中父进程通过管道将100行传递给子进程。然后,子进程应使用生成的行并在这些行上执行命令行程序more
。
但是,当我尝试运行该程序时,它只是冻结。我小心翼翼地关闭了两个进程都没有使用的所有描述符,但我并不真正理解可能导致它的原因。
代码:
int main(void){
int fd[2];
if (pipe(fd) == -1){
perror("Error creating pipe");
return 1;
}
dup2(fd[1], STDOUT_FILENO);
int i;
for (i = 1; i <= 100; i++){
printf("Line %d\n", i);
}
close(fd[1]);
pid_t pid = fork();
if(pid == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execlp("more", "more",(char*) NULL);
fprintf(stderr, "Failed to execute 'more'\n");
exit(1);
}
wait(NULL);
return 0;
}
答案 0 :(得分:0)
我小心地关闭了两个进程都没有使用的所有描述符
不是。
dup2(fd[1], STDOUT_FILENO);
在这里,您stdout
fd[1]
的副本。
close(fd[1]);
在此关闭fd[1]
,但stdout
仍处于打开状态。
然后你fork
。此时,两个进程都可以通过stdout
访问管道的写端。
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
在子流程中,您将fd[0]
复制到stdin
并关闭fd[0]
。
然后,当您执行more
时,它仍然可以访问管道的两端(通过stdin
/ stdout
)。
同时,您的父流程可以访问管道的两端(通过fd[0]
/ stdout
)。
实际上你什么都没有关闭。
还有第二个问题:您的父进程写入stdout
,它绑定到管道的写端,没有人读取它。根据您编写的内容,stdout
是行缓冲还是块缓冲,stdout
缓冲区有多大,以及管道本身可以存储多少,这本身就会死锁。如果管道已满,并且周围没有人可以从中读取,printf
将会阻止。
要解决此问题,请不要在父进程中dup2
,也不要在子进程启动之前写入管道。
int main(void){
int fd[2];
if (pipe(fd) == -1){
perror("Error creating pipe");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("Error spawning process");
return 2;
}
if (pid == 0) {
close(fd[1]); /* close write end of the pipe in the child */
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execlp("more", "more", (char*)NULL);
fprintf(stderr, "Failed to execute 'more'\n");
exit(1);
}
close(fd[0]); /* close read end of the pipe in the parent */
FILE *fp = fdopen(fd[1], "w");
if (!fp) {
perror("Error opening file handle");
return 3;
}
for (int i = 1; i <= 100; i++){
fprintf(fp, "Line %d\n", i);
}
fclose(fp); /* flush and close write end of the pipe in the parent */
wait(NULL);
return 0;
}