【发布时间】:2017-05-17 04:29:12
【问题描述】:
这是我试图了解如何在两个子进程之间进行正确管道的尝试。我只是试图将一个 Linux 命令的输出传递给另一个(ls 到 cat)并让程序成功返回。但是,我猜测分叉的第二个孩子被卡住了,父母永远在等待这个孩子。我一直在摆弄这段代码,试图找出它卡住的原因。在 C 系统编程方面,我是一个菜鸟,但我正在努力学习。
有人知道为什么程序不退出,而是挂在 cat 上吗?
任何帮助将不胜感激。
谢谢。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
char *a[2] = {"/bin/ls", NULL};
char *b[2] = {"/bin/cat", NULL};
char *envp[2] = {getenv("PATH"), NULL};
int fd[2], status;
pipe(fd);
int old_std_out = dup(1);
int old_std_in = dup(0);
dup2(fd[1], 1);
int pid = fork();
switch(pid)
{
case -1:
perror("Forkscrew");
exit(1);
break;
case 0:
execve(a[0], a, envp);
exit(0);
break;
default:
waitpid(-1, &status, 0);
dup2(old_std_out, 1);
break;
}
dup2(fd[0], 0);
pid = fork();
switch(pid)
{
case -1:
perror("Forkscrew");
exit(1);
break;
case 0:
execve(b[0], b, envp);
exit(0);
break;
default:
waitpid(-1, &status, 0);
dup2(old_std_in, 0);
break;
}
printf("\n");
return 0;
}
【问题讨论】:
-
你不是在处决两只猫吗?你先分叉,然后再分叉?
-
一个更微妙的死锁(但这种死锁总是发生,不仅仅是在管道缓冲区已满时)与管道的读取端相关联。当
ls终止时,它会关闭管道写入端的副本。但是,您的父进程和您的cat-进程仍然有一个写入端的副本(实际上,父进程末尾的printf()会写入它......) ,因此来自cat中管道的read()将阻塞,直到关闭写入端,这永远不会发生,因为cat甚至不知道写入端的文件描述符,并且父级不会终止。 -
@SamiKuhmonen
exec()如果成功则不会返回。 -
@user3499524:啊,对,我没看到你
dup2(old_std_out, 1);回来。这不是做这种事情的常用方法,你通常应该只重定向文件描述符之后fork(),那么你就不需要这个了。由于您dup2(fd[1], 1);在第一个fork()之前,您保留了大约两个管道写入端的副本。一个,你通过dup2(old_std_out, 1);隐式关闭,另一个留下。 -
可能不应该在评论中做出全面的回答。不幸的是,我现在没有时间,我可能在几个小时内。无论如何,要快速修复第二个死锁,请在第二个
fork()之前添加close(fd[1]),看看会有帮助。