简体   繁体   中英

How to use pipes correctly with child processes?

//I want to execute pwd|sort > file.txt

char commands[2][30] = {"pwd", "sort"};
char directory [2][30] = {"/usr/bin/pwd", "/usr/bin/sort"}
char outputFile[30] = "file.txt"
int totalCommands = 2;
bool isOutputFilePresent = true;

//creating two pipes
int fd1[2];
int fd2[2];
pipe(fd1);
pipe(fd2);
//Closing the writing ends but keeping the reading ends open as closing them will destroy both the pipes
close (fd1[1]);
close (fd2[1]);

//loop to execute each command by creating a child process in each iteration
for (int i = 0; i < totalCommands; ++i)
{
    pid_t pid = fork();
    if (pid == 0)
    {
        if (i == totalCommands - 1)
        {
            if (i%2 == 0)
            {
                close(fd1[1]);
                close(fd2[0]);
                dup2(fd1[0], 0);
                dup2(fd2[1], 1);
            }
            else
            {
                close(fd2[1]);
                close(fd1[0]);
                dup2(fd2[0], 0);
                dup2(fd1[1], 1);
            }
        }
        else
        {
            if (i%2 == 0)
            { 
                close(fd2[0]);
                close(fd2[1]);
                close(fd1[1]);
                dup2(fd1[0], 0);
            }
            else
            {
                close(fd1[0]);
                close(fd1[1]);
                close(fd2[1]);
                dup2(fd2[0], 0);
            }
            if(isOutputFilePresent)
            {
                int outputFD = open (outputFile, O_WRONLY | O_CREAT);
                dup2(outputFD, 1);
            }

        }
        execv(directory[i], commands[i]) //ignore the fact that i am passing command name instead of argument vector
    }
    wait(NULL);
}

As the child process will inherit its own FDs of the pipe, I closed unused pipes in each process and by using dup2, assigned stdout and stdin FDs to it. But this code has a logical error and I guess its because of not using the pipes correctly. So where am I mistaken in the concept of pipes and what could be the solution to this problem. Thanks!

You close the write end of the pipes immediately after opening them. Therefore nothing can write to those pipes:

pipe(fd1);
pipe(fd2);
//Closing the writing ends but keeping the reading ends open as closing them will destroy both the pipes
close (fd1[1]);
close (fd2[1]);

Do this:

  1. Create two pipes: A and B
  2. Fork/spawn new child process
  3. Parent closes write-end of A and read-end of B
  4. Child closes read-end of A and write-end of B

Thus the child writes to A, and the parent reads from A. The parent writes to B, and the child reads from B.

The man page for pipe(2) give you example code that shows you how to do this:

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int
main(int argc, char *argv[])
{
   int pipefd[2];
   pid_t cpid;
   char buf;

   if (argc != 2) {
       fprintf(stderr, "Usage: %s <string>\n", argv[0]);
       exit(EXIT_FAILURE);
   }

   if (pipe(pipefd) == -1) {
       perror("pipe");
       exit(EXIT_FAILURE);
   }

   cpid = fork();
   if (cpid == -1) {
       perror("fork");
       exit(EXIT_FAILURE);
   }

   if (cpid == 0) {    /* Child reads from pipe */
       close(pipefd[1]);          /* Close unused write end */

       while (read(pipefd[0], &buf, 1) > 0)
           write(STDOUT_FILENO, &buf, 1);

       write(STDOUT_FILENO, "\n", 1);
       close(pipefd[0]);
       _exit(EXIT_SUCCESS);

   } else {            /* Parent writes argv[1] to pipe */
       close(pipefd[0]);          /* Close unused read end */
       write(pipefd[1], argv[1], strlen(argv[1]));
       close(pipefd[1]);          /* Reader will see EOF */
       wait(NULL);                /* Wait for child */
       exit(EXIT_SUCCESS);
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM