0
votes

I have a multiple processes in progs and I wish to pipe the output from one process to another sequentially. I believe I have already linked the stdin of a process to the read end of a previous process, and linked the stdout to the write end of the pipe. I still am not seeing an output. Am I missing something with the links here?

  int pipeFds[numProg][2];
  
  for (int i = 0; i < numProg; i++) {
    if (pipe(pipeFds[i]) != 0) { // create pipe for each process
      printf("Failed to create pipe!");
      exit(1);
    }
    child_pid = fork();
    if (child_pid == -1) {
      printf("Error while creating fork!");
      exit(1);
    } 
    if (child_pid == 0) {
      if (i == 0) { 
        close(pipeFds[i][READ_END]); // close STDIN first process since it does not read
      } else { 
        // change stdin to read end of pipe for intermediary processes
        close(pipeFds[i]);
        dup2(pipeFds[i - 1][READ_END], STDIN_FILENO);
      }
      dup2(pipeFds[i][WRITE_END], STDOUT_FILENO); // change stdout to write end of pipe
      execvp(progs[i][0], (char *const * )progs[i]);
    } else {
      // parent process stuff
    }
  }
  
  // Close pipes except last pipe for EOF
  for (int i = 0; i < numProg - 1; i++) {
    close(pipeFds[i][READ_END]);
    close(pipeFds[i][WRITE_END]);
  }

2

2 Answers

0
votes

Remember you need to close all pipes, in each process, for it to work.

Example:

If numProg=2 you create 2 pipes and 2 child processes. Adding the parent, there a 3 processes running, and in each of them you eventually need to close all pipes.

For child_pid==0 you close the [READ_END] but never the [WRITE_END].

For child_pid==1 you do a close(pipeFds[1]). You need to specify [READ_END] and [WRITE_END].

Then each child process exits via execvp which, however, may return control if it fails. From the man page:

The exec() family of functions replaces the current process image with a new process image. .. The exec() functions only return if an error has occurred.

So you may want to add a _exit(0); after execvp to ensure each child process exits properly even if execvp fails.

The parent process closes all pipes but the last. So in the example of NumProg=2, [READ_END] and [WRITE_END] of pipeFd[1] both are never closed.

Lastly, the parent process should wait for all child processes to close (using while(wait(NULL) != -1);) otherwise you may end up with zombie or orphan processes.

0
votes
  1. your code contains a stray close(pipeFds[i]);

  2. you have to close the pipes within the // parent process stuff. With your code, every child keeps the pipeFds of the previous children open. E.g.

     } else {
         // parent process stuff
         if (i > 0)
             close(pipeFds[i - 1][READ_END]);
         close(pipeFds[i - 1][READ_END]);
     }
    
  3. it might be more effective to have a single fds[2] pair instead of numProg ones.