我使用管道fork和exec来实现任意两个shell程序的通用管道。我特别使用ls|grep来测试它。它有效,数据被复制到grep,grep搜索匹配项,然后将它们输出到stdout。然而,在那之后,程序就挂起了。
这是我在检测到管道时执行的代码。我分叉,然后再次分叉,因为我希望第一个分叉的父进程在exec调用后继续运行。我相信,由于调试代码,在执行grep的exec()调用之后,什么都没有发生。
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of childn");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not foundn", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd childn");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not foundn", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reachedn");
case ENOMEM:
printf("Cannot fork process: Out of memoryn");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parentn");
}
if(PID == -1){
printf("ERROR:n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reachedn");
case ENOMEM:
printf("Cannot fork process: Out of memoryn");
}
return 1;
}
}
下面是我对这个问题的解决方案。我不确定这是否是一个永久的解决方案。我甚至不能100%确定我对为什么这是有效的,而之前的代码不是有效的原因。我所做的只是将等待输入的命令从管道(grep)切换到父进程,并将向管道(ls)写入输出的命令切换到子进程。
我的理由是:我使用ls|grep进行测试,ls在grep的子进程设置之前就已经完成了对管道的写入,因此从未关闭管道,grep也从未收到EOF。通过改变它们的位置,grep已经准备好了,并在运行ls的进程设置好时等待ls写入。我相信这是一个非常不完美的解决方案,所以对于将来读到这篇文章的人,我希望你能提供一个更好的答案。如果我对它为什么有效的推理是正确的,我可以想到很多情况下它仍然会出错。
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of childn");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not foundn", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd childn");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not foundn", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reachedn");
case ENOMEM:
printf("Cannot fork process: Out of memoryn");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parentn");
}
if(PID == -1){
printf("ERROR:n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reachedn");
case ENOMEM:
printf("Cannot fork process: Out of memoryn");
}
return 1;
}
}