简体   繁体   English

在 C 中使用两个管道读取后无法退出循环(进程)

[英]Unable to exit loop after reading using two pipes in C (processes)

I have taken a look at this and also this stack overflow links.我已经看过这个这个堆栈溢出链接。

I am having trouble understanding the process for closing write ends of pipes.我无法理解关闭管道写端的过程。 In the code below, I have 3 processes, one parent, a child of the parent, and a child of the child.在下面的代码中,我有 3 个进程,一个父进程,一个父进程的子进程,一个子进程的子进程。 I am trying to simulate a pipe for the command - cat xxx | grep 28 | sort我正在尝试为命令模拟管道 - cat xxx | grep 28 | sort cat xxx | grep 28 | sort cat xxx | grep 28 | sort . cat xxx | grep 28 | sort I have written some code for this, and it essentially creates the sorts, "grips"/filters and prints my input, but it hangs at the end.我为此编写了一些代码,它基本上创建了排序、“夹点”/过滤器并打印了我的输入,但它在最后挂起。 I have to ctrl + c to exit.我必须 ctrl + c 退出。 My code is a little messy, but if you can help me spot the problem that would be nice.我的代码有点乱,但如果你能帮我发现问题就好了。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

/**
 * Executes the command "cat scores | grep Lakers".  In this quick-and-dirty
 * implementation the parent doesn't wait for the child to finish and
 * so the command prompt may reappear before the child terminates.
 *
 */

int main(int argc, char **argv)
{
  int pipefd[2];
  int pipefd2[2];
  int pid;

  char *cat_args[] = {"cat", "scores", NULL};
  char *grep_args[] = {"grep", "28", NULL};
  char *sort_args[] = {"sort", NULL};
  

  // make a pipe (fds go in pipefd[0] and pipefd[1])

  if (pipe(pipefd) != 0){
    return 1;
  }

   if (pipe(pipefd2) != 0){
    return 1;
  }

  pid = fork();

  if (pid < 0) 
    { 
    fprintf(stderr, "fork Failed" ); 
    exit(EXIT_FAILURE);
    } 
  else if (pid == 0)
    {     
    
    int pid2;
    pid2 = fork();
    
    if (pid2 < 0){
      fprintf(stderr, "fork Failed" ); 
      return 1;
    }
    else if (pid2 == 0){
      // replace standard input with input part of pipe
//       close(0);
//       close(pipefd[1]);
//       close(pipefd2[1]);
      dup2(pipefd2[0], 0);

      // close unused hald of pipe
      
      close(pipefd2[0]);
      close(pipefd[1]);
      close(pipefd2[1]);
      close(pipefd[0]);

      // execute grep

      execvp("sort", sort_args);
      close(pipefd[1]);
      close(pipefd2[1]);
      exit(0);
    }else{
      // replace standard input with input part of pipe
      
//       close(pipefd[1]);
//       close(pipefd2[1]);
      dup2(pipefd[0], 0);
      dup2(pipefd2[1], 1);

      // close unused hald of pipe
      close(pipefd[0]);
      close(pipefd2[1]);
      close(pipefd[1]);
      close(pipefd2[0]);

      // execute grep

      execvp("grep", grep_args);
      waitpid(pid2, NULL, 0);
      
     
      close(pipefd[1]);
      close(pipefd[0]);
      close(pipefd2[1]);
      close(pipefd2[0]);
      exit(0);
      waitpid(pid2, NULL, 0);
    }
    }
  else
    {
//       close(pipefd[1]);
//       close(pipefd2[1]);
      dup2(pipefd[1], 1);

      // close unused unput half of pipe
      
      close(pipefd[1]);
      close(pipefd[0]);
      close(pipefd2[1]);
      close(pipefd2[0]);
      // execute cat

      execvp("cat", cat_args);
    
    exit(0);
    waitpid(pid, NULL, 0);
    }
  
  close(pipefd[1]);
  close(pipefd[0]);
  close(pipefd2[1]);
  close(pipefd2[0]);

}

here is the output I am getting.这是我得到的输出。 Not sure it is relevant but as you can see, the result is sorted by team name.不确定它是否相关,但如您所见,结果按团队名称排序。 It just doesn't terminate.它只是没有终止。

Houston       44      28      .611
Indiana 45      28      .616
Oklahoma City   44      28      .611
Utah    44      28      .611
^C

Calling execvp replaces the current process image with a new process image.调用execvp 会用新的进程映像替换当前进程映像。 If no error occured, your code will never reach any line after that, so your close() and waitpid() function calls are useless.如果没有发生错误,您的代码在此之后将永远不会到达任何行,因此您的close()waitpid()函数调用是无用的。

EDIT编辑

Here's a fully functional code to your problem.这是针对您的问题的功能齐全的代码。 The comments should be self explanatory.评论应该是不言自明的。 Notice that the command executing order is different and I'm waiting for processes to finish.请注意,命令执行顺序不同,我正在等待进程完成。

Reading from an empty pipe will block until there is some data to read or an error occured, so this is not the only solution.从空管道读取将阻塞,直到有一些数据要读取或发生错误,所以这不是唯一的解决方案。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    static void die (const char *msg) {
        perror (msg);
        exit (EXIT_FAILURE);
    }
    
    int main (int argc, char** argv) {
        int pipefd[2];
        int pid;
        char *cat_args[] = {"cat", "scores", NULL};
        char *grep_args[] = {"grep", "28", NULL};
        char *sort_args[] = {"sort", NULL};
    
        //make a pipe (file descriptor to read is pipefd[0], fd to write is pipefd[1])
        if (pipe (pipefd) < 0) 
            die ("creating a pipe failed");
        pid = fork();
        if (pid < 0)
            die ("fork");
        else if (pid == 0) {
        //child process
        int pipefd2[2]; //only visible to the affected processes
        if (pipe (pipefd2) < 0)
            die ("pipe");
        int pid2;
        pid2 = fork();
        if (pid2 < 0)
            die ("fork");
        else if (pid2 == 0) {
            //child of child will execute cat command
            close (pipefd2[0]); //we only need to write to the second pipe. close its reading end
    
            //first pipe is for communication between parent and grandparent only
            close (pipefd[0]);
            close (pipefd[1]);
    
            dup2 (pipefd2[1], STDOUT_FILENO); //write the output to the second pipe instead of the standard output
            close (pipefd2[1]); //close writing end of second pipe
    
            execvp("cat", cat_args); //execute cat command
            die ("execvp should never return");
    
        }
        else {
            //child process will execute the grep command
            close (pipefd2[1]); // we only need to read from the second pipe. close its writing end
            close(pipefd[0]); //we won't read from the first pipe
    
    
            waitpid (pid2, NULL, 0); //wait for cat command to finish
    
            dup2 (pipefd2[0], STDIN_FILENO); //read from the second pipe instead of the stdin
            close (pipefd2[0]); //child finished. close reading end of second pipe
    
            dup2 (pipefd[1], STDOUT_FILENO); //write the results of grep command to first pipe instead of standard output
            close (pipefd[1]); //we dup2 the output, close the writing end of first pipe
    
            execvp ("grep", grep_args);
            die ("execvp should never return");
    
        }
        } else {
        //parent process will execute the sort command
        close (pipefd[1]); //we won't write to the first pipe
    
    
        waitpid (pid, NULL, 0); //wait for child to write grep output to the first pipe
    
        dup2 (pipefd[0], STDIN_FILENO); //read from the first pipe instead of stdin
        close (pipefd[0]); //child finished. close reading end of first pipe
    
        execvp ("sort", sort_args); //execute command
        die ("execvp should never return");
        }
        //exit (EXIT_SUCCESS); we don't need this. the programm will never reach this line
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM