C - 单壳管道实施不断在终端中被绞死

时间:2015-02-19 03:26:17

标签: c linux shell pipe implementation

我一直在尝试在shell程序中实现管道结构,如果我执行简单的命令,它可以工作,例如" hello |转"

但是当我尝试做的时候它就会挂起" head -c 1000000 / dev / urandom | wc -c" (忽略引号)

我的实施是:

             int fd[2];
             pipe(fd);
            // IN CHILD 
           // Piping for the first command
              if (isPiped && (e == list_begin(&p->commands))) 
               {

                  close(fd[0]);
                  dup2(fd[1], 1);
                  close(fd[1]);

               }

               // Last command in the pipe
               else if (isPiped && (list_next(e) ==   list_tail(&p->commands))) 
               {

                  close(fd[1]);
                  dup2(fd[0], 0);
                  close(fd[0]);

               }

      // IN PARENT
     if (isPiped && (e == list_begin(&p->commands))) 
           {
             close(fd[1]);
           }

           else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
           {
              close(fd[0]);
           }

我已经被教会在我完成使用之后总是关闭文件描述符,我认为这就是我正在做的事情 - 但我有一个文件描述符泄漏到某处,我无法弄清楚在哪里。我一直试图做很多关闭和重复fd的组合,但无济于事。

为了进一步提出一个完整的问题,这是主要的相关代码:

我这样做的方法是使用一个列表结构,将每个命令/作业添加到列表中。变量" e"是列表的一个元素。

int main(int ac, char *argv[]) {

int numPipes = list_size(&commands) - 1;
bool isPiped = false;
if (numPipes > 0)
   isPiped = true;

int fd[2];
pipe(fd);

pid_t pid = fork();
// In child
if (pid == 0) 
{
    if (isPiped && (e == list_begin(&p->commands))) 
    {       
      close(fd[0]);
      dup2(fd[1], 1);
      close(fd[1]);              
    }

   // Last command in the pipe
   else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
   {            
    close(fd[1]);
    dup2(fd[0], 0);
    close(fd[0]);             
   }
// command is a struct. I have it set up so that the terminal can read in what the user inputs
execvp(command->argv[0], command->arg);

 }
// In parent
 if (isPiped && (e == list_begin(&p->commands))) 
 {
  close(fd[1]);
 }

 else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
 {
   close(fd[0]);
 }
 int status;
 waitpid(-1, &status, WUNTRACED);
}

这就是我的管道算法。其余的仅用于其他内置作业,例如前景,后台,终止命令和io重定向。 非常感谢!

1 个答案:

答案 0 :(得分:0)

父进程应在启动两个子进程后关闭管道的两端。如果它没有关闭管道的写入端,那么从管道读取的子节点将永远不会获得EOF,因此它永远不会终止。如果它没有关闭管道的读取端,但正在读取的子节点在读取所有输入之前终止,则正在写入的子节点将永远不会出现错误并将阻塞,等待父节点读取父母无意阅读。

所以,父母只需要:

close(fd[0]);
close(fd[1]);