在C中实现多个管道

时间:2015-10-12 12:58:28

标签: c shell pipe file-descriptor

任何人都可以解释为什么我的以下代码试图实现多个管道不正确?我正在实施亲子关系,因此不允许父子关系,即所有孩子应该并行运行。 当我输入命令ls |猫| cat,ls的内容输出,但提示仍然提示我输入,即使我输入另一个字符也不会停止。 我这样做是错误的吗?

    int i;
    int pipefd[num_of_pipe][2];
    pid_t child_pid[num_of_child];

    for (i = 0; i < num_of_child; i++) {
      pipe(pipefd[i]);
      if ((child_pid[i] = fork()) == 0) {
        if (i == 0) {
          close(pipefd[i][0]);
          dup2(pipefd[i][1], STDOUT_FILENO);
          close(pipefd[i][1]);
          /* execvp something; */
        } else if (i == num_of_child - 1) {
          close(pipefd[i - 1][1]);
          dup2(pipefd[i - 1][0], STDIN_FILENO);
          close(pipefd[i - 1][0]);
          /* execvp something */
        } else {
          close(pipefd[i - 1][1]);
          dup2(pipefd[i - 1][0],0);
          close(pipefd[i - 1][0]);
          close(pipefd[i][0]);
          dup2(pipefd[i][1],1);
          close(pipefd[i][1]);
          /* execvp something */
        }
      }
    }

    int k;
    for (k = 0; k < num_of_child; k++) {
      waitpid(child_pid[k], NULL, WUNTRACED);
      printf("the %dth child returns\n", k + 1);
    }

    int j;
    for (j = 0; j < num_of_pipe; j++) {
      close(pipefd[j][0]);
      close(pipefd[j][1]);
    }
  }

1 个答案:

答案 0 :(得分:1)

问题在于,您的两个cat进程正在等待其标准输入上的更多数据,因为并非所有管道写入结束的文件描述符副本都会关闭。这是因为父进程构建并保留所有管道文件描述符的数组,并且只有在分配所有子进程后才关闭它们。因此,每个子节点都继承了父到目前为止创建的每个打开文件描述符,而不仅仅是那些供自己使用的文件描述符。在关闭管道写入端的所有FD之前,在读取端不会检测到EOF。

因此,特别地,第三子进程具有用于由第二子进程读取的管道的写入端的打开文件描述符。它会在退出时关闭,但它不会退出,因为第二个进程保持打开供给第三个管道的管道的写入端。如果管道更长,问题会更严重。

您应该通过让主进程在不再需要时立即关闭文件描述符来处理问题,这样它们就不会被继承。使用您当前的代码结构,您可以在fork循环的底部执行此操作。

作为次要问题,如果您确实依赖它们没有失败,则应始终检查函数调用的返回值是否有错误指示符。