【发布时间】:2016-05-14 06:16:14
【问题描述】:
我正在尝试使用管道将执行的 1 个命令的标准输出链接到另一个命令的标准输入。例如模仿(cmd1 | cmd2)
以下是我的代码的精简版。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argC, char *argv[])
{
//Run first command
int fds[2];
if (pipe (fds) < 0) { //Create pipe
fprintf (stderr, "Pipe Failed\n");
}
int pid;
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 1 Failed\n");
exit (1);
}
if (pid == 0) { //First child proccess
close (fds[0]); //Close input end of pipe
dup2 (fds[1], STDOUT_FILENO); //Set stdout to output pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 1 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("ls", "ls", NULL);//Causes hang
fprintf (stderr, "Exec 1 failed\n");
} else { //First parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 1 to finish
fprintf (stderr, "Back to parent 1\n");
}
//Run second command
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 2 failed\n");
}
if (pid == 0) { //second child proccess
dup2 (fds[0], STDIN_FILENO); //Set stdin to input pipe
close (fds[0]); //Close input end of pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 2 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("wc", "wc", NULL);//Causes hang
fprintf (stderr, "Exec 2 failed\n");
} else { //second parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 2 to finish
fprintf (stderr, "Back to parent 2\n");
//Done with pipes
close (fds[0]);
close (fds[1]);
}
return 0;
}
在程序中,我尝试创建一个管道并将第一个 execs 标准输出路由到第二个标准输入。尝试使用 ls | 运行程序时wc 作为我的执行官,我的程序挂在第二个执行官上。但是,当我使用一个简单的程序“./addone”作为我的 exec 时,整个执行都会正确完成。
其中“addone”是一个小程序:
#include<stdio.h>
int main(){
int value = 0;
scanf("%d", &value);
value++;
printf("%d\n", value);
}
有人建议我的问题可能是有一个输入管道处于打开状态,但我无法确定会发生这种情况的位置,并且它没有解释为什么我的程序在使用我的简单测试程序时运行完美。
任何有关导致此挂起的原因的建议将不胜感激。
【问题讨论】:
-
您需要在父进程中关闭管道末端。因为
pipe是在fork之前调用的,所以它在父进程和子进程中都打开。对于您的简单程序来说这不是问题,因为它不会像wc那样循环等待EOF。如果管道仍被任何进程保持打开状态,EOF永远不会出现。 -
我不是已经用 close(fds[0]);关闭(fds[1]);或者我应该将它们移到父级的等待语句之前?
-
你确定你没有从你的程序中删除一些重要的东西吗?在您发布的示例中,只要正在执行的程序将任何内容写入标准输出,我希望它在第一个 waitpid 处挂起 - 子进程中的 printf 会阻塞,因为没有从管道的另一端读取任何内容,而父母会反过来阻止等待孩子。建议:1)立即关闭父子和子中未使用的管道末端(即在第一次分叉后关闭父中的 fds[1] 等。2)在开始第二个之前不要等待第一个子,最后都等待而是
-
@Killedan9 是的,您必须在
waitpitd之前执行此操作。否则子进程不会退出,他waitpid永远不会解除阻塞。 -
@davlet “子进程中的 printf 会阻塞,因为管道另一端没有读取任何内容”。我不认为这是正确的。也许您正在考虑fifo。管道没有这种行为。无论如何,正如已经指出的那样,父进程的两端都是开放的。