【问题标题】:C++ pipes between multiple children多个孩子之间的 C++ 管道
【发布时间】:2011-11-01 21:41:51
【问题描述】:

我正在做一个项目,除了一个小(大)问题外,我大部分都已经弄清楚了。我似乎无法弄清楚如何在任意数量的孩子之间创建管道。

例如,我使用命令行参数来确定将产生多少个孩子。第一个孩子没有输入但有输出,最后一个孩子输出到 STD 输出。我需要将值传递给第一个孩子,然后依次传递给每个孩子。这是我得到的:

#include <errno.h>
#include <cstdio>
#include <iostream>
#include <sys/wait.h>

using namespace std;

int main(int argc, char *argv[]) {
    pid_t childpid;
    int x2ypipe[2];
    pipe(x2ypipe);
    if(x2ypipe==0) {
        cout<<"ERROR:"<<errno<<endl;
    }
    int y2zpipe[2];
    pipe(y2zpipe);
    if(y2zpipe==0) {
        cout<<"ERROR:"<<errno<<endl;
    }
    pid_t xchild =fork();
    if(xchild==0) {
        dup2(x2ypipe[1],STDOUT_FILENO);
        close(x2ypipe[0]);
        close(x2ypipe[1]);
        int a=execl(argv[1],argv[1], (char*)NULL);
        if(a==-1) {
            perror("The following error occurred at A");
        }
    }
    for(int i=2; i<(argc-1); i++) {
        childpid =fork();
        if(childpid==0) {
            dup2(x2ypipe[0],STDIN_FILENO);
            close(x2ypipe[0]);
            close(x2ypipe[1]);
            //direct y2z pipe to standard output and replace the child with the program part2
            dup2(x2ypipe[1],y2zpipe[1]);
            dup2(y2zpipe[1],STDOUT_FILENO);
            close(y2zpipe[0]);
            close(y2zpipe[1]);
            int b=execl(argv[i],argv[i],(char *)NULL);
            if(b==-1) {
                perror("The following error occurred at B");
            }
        }
    }
    pid_t zchild =fork();
    if(zchild==0) {
        dup2(y2zpipe[0],STDIN_FILENO);
        close(y2zpipe[0]);
        close(y2zpipe[1]);
        int c=execl(argv[argc-1],argv[argc-1],(char *)NULL);
        if(c==-1) {
            perror("The following error occurred at C");
        }
    }
    close(x2ypipe[0]);
    close(x2ypipe[1]);
    wait(NULL);
    wait(NULL);
    wait(NULL);
}

现在我只将三个程序传递给 argv[] 并且它工作正常。我将不得不在我的 for 循环中添加一个 if 语句来检查 i 的最后/最高可能值,以将 y2z 管道连接到 zchild。我在 for 循环中将孩子们相互连接起来时遇到了麻烦。我将如何从最后一个孩子为每个孩子创建一个新管道?

【问题讨论】:

  • 哇,18 行 just #includes 确实占据了 80% 的屏幕空间。你听说过最小的工作示例吗?
  • 请不要#include C 和 C++ 版本的标头。选择其中一个并坚持下去。
  • 我之前已经为 C 回答过这个问题:How do I chain stdout in one child process to stdin in another child in C? 这可能对你有帮助,因为它看起来不像你真的在使用 C++(提示:使用 cout 没有' t 使它成为 C++)。
  • 那里,FTFY:14 个冗余包括消失(g++,linux)。剩下的恐怕超出了我的维修能力
  • @sehe:我喜欢你的名字在你写有趣的 cmets 时看起来像“呵呵”

标签: c++ fork pipe


【解决方案1】:

也许这会有所帮助。请注意我在 for 循环中如何调用 pipe(),因此我不必为管道对考虑新的“x2y”、“y2z”、“z2omega”等名称。

还要注意我是如何使用来自 for 循环外部的变量 prevfd 将先前迭代的管道文件描述符携带到下一次迭代中的。以及它如何指向“/dev/null”。

最后,请注意我是如何在循环中准确地调用 wait() 的次数,而不是写 3 次(或 4 次或 5 次或 ... 1,397 次)。

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdlib>
#include <cstdio>
#include <sys/wait.h>

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

  int prevfd;

  prevfd = open("/dev/null", O_RDONLY);

  if(prevfd < 0) {
    perror("/dev/null");
    exit(1);
  }

  for(int i = 1; i < argc; ++i) {
    int pipefd[2];
    int kid;

    if(i != argc-1 && pipe(pipefd)) {
      perror("pipe");
      break;
    }

    if(!fork()) {
      dup2(prevfd, 0);
      close(prevfd);
      if(i != argc-1) {
        dup2(pipefd[1], 1);
        close(pipefd[0]);
        close(pipefd[1]);
      }
      execl(argv[i], argv[i], (char*)0);
      perror(argv[i]);
      exit(1);
    }

    close(prevfd);
    prevfd = pipefd[0];
    close(pipefd[1]);
  }
  while(wait((int*)0) != -1)
    ;
  return 0;
}

【讨论】:

    【解决方案2】:

    您需要在每对连接的进程之间使用单独的管道。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-26
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多