user975044
user975044

Reputation: 385

C++ pipes between multiple children

I am working on a project and I got it mostly figured out except for one minor(big) problem. I can't seem to figure out how to create pipes between any number of children.

for example I am taking in command line arguments to determine how many children will be produced. The first child doesn't have input but has output and the last child outputs to STD output. I need to pass values into the first child and into each child after that in order. Here is what i got:

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

now right now I am only passing in three programs in to the argv[] and it works fine. I will have to add a if statement in my for loop to check for the last/highest possible value of i to connect the y2z pipe to the zchild. What I am having trouble doing it connecting the children to each other within the for loop. How would I go about creating a new pipe for each child from the last child?

Upvotes: 0

Views: 3228

Answers (2)

Robᵩ
Robᵩ

Reputation: 168616

Maybe this will help. Notice how I call pipe() inside my for loop, so I don't have to think of new "x2y", "y2z", "z2omega", etc, etc names for the pipe pairs.

Also notice how I used a variable prevfd from outside the for loop to carry the previous iterations's pipe file descriptor into the next iteration. And how it points to "/dev/null" to start with.

Finally, notice how I call wait() precisely as many times as I need to, in a loop, rather than writing it 3 (or 4 or 5 or ... 1,397) times.

#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;
}

Upvotes: 1

You need a separate pipe between each pair of connected processes.

Upvotes: 0

Related Questions