c - 在C中实现多管道

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

最佳答案

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

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

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

其次,如果您实际上依赖函数调用的返回值来确保它们不会失败,那么您应该始终检查函数调用的返回值是否有错误指示符。

关于c - 在C中实现多管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33081748/

相关文章:

c - 如何用静态库编译gcc?

java - 以增量方式生成随机数

linux - zip 文件的输出存档注释

javascript - 如何使用 Unix 将 Node.js 脚本连接在一起 |管道(在命令行上)?

Angular2 如何使用管道将年份转换为年龄

应用程序提示符上的 Python 子进程输出阻塞

c - 分析valgrind输出: "invalid free()"

c - 在cuda中执行一次部分代码

linux - 我可以避免使用 FIFO 文件加入 Bash 管道的末尾以存储在当前 shell 的变量中吗?

linux - shell 内的 shell 脚本 shell