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

时间:2022-05-11 17:31:34

I've been trying to implement a piping structure in a shell program and it works if I do simple commands, such as "hello | rev"

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

But it hangs when I try to do "head -c 1000000 /dev/urandom | wc -c" (Ignore quotes)

但是当我尝试“head -c 1000000 / dev / urandom | wc -c”(忽略引号)时它会挂起

My implementation is:

我的实施是:

             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]);
           }

I've been taught to always close a file descriptor after I'm done using it, and I thought that's what I'm doing - but I'm having a file descriptor leak somewhere and I can't figure out where. I've been trying to do many combination of closing and dup2'ing the fd, but to no avail.

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

To further give a complete question, this is the main relevant code:

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

The way I'm doing it is to use a list structure that adds each command/job onto a list. The variable "e" is an element of the list.

我这样做的方法是使用一个列表结构,将每个命令/作业添加到列表中。变量“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);
}

That's all there is to my pipe algorithm. The rest are just for other built in jobs, such as foreground, background, kill commands and io redirection. Thanks so much!

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

1 个解决方案

#1


0  

The parent process should close both ends of the pipe after it has launched the two children. If it doesn't close the writing end of the pipe, the child that is reading from the pipe will never get EOF, so it will never terminate. If it doesn't close the reading end of the pipe but the child that is reading terminates before it has read all the input, the child that is writing will never get an error and will block, waiting for the parent to read when the parent has no intention of ever reading.

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

So, the parent simply needs:

所以,父母只需要:

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

#1


0  

The parent process should close both ends of the pipe after it has launched the two children. If it doesn't close the writing end of the pipe, the child that is reading from the pipe will never get EOF, so it will never terminate. If it doesn't close the reading end of the pipe but the child that is reading terminates before it has read all the input, the child that is writing will never get an error and will block, waiting for the parent to read when the parent has no intention of ever reading.

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

So, the parent simply needs:

所以,父母只需要:

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