Search code examples
cmacospipeforkfile-descriptor

Child-Process execution order seems wrong, but works


Why does the following code execute the command:

"cat /etc/passwd | wc -l"

and not

"wc -l | cat /etc/passwd"?

Even though the debugging statements are in the order

b

a

 int main() {
    pid_t pid;
    int fd[2];

    int stdOut = dup(1);

    pid = fork();
    if (pid == 0) {
        pipe(fd);
        pid = fork();
        if (pid == 0) {
            close(fd[0]);
            dup2(fd[1], STDOUT_FILENO);
            close(fd[1]);

            write(stdOut, "a\n", 2);

            execlp("cat", "cat", "/etc/passwd", NULL);
        }
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);

        write(stdOut, "b\n", 2);

        execlp("wc", "wc", "-l", NULL);
    }
    wait(NULL);
    return 0;
}

Solution

  • The use of pipe, dup2 and close determines how the two processes are connected, not the order of execution. The process which runs first may block in a read or write access to the pipe until the other one sends or receives data respectively.

    The execution order cannot be wrong because it is not specified. Any of parent or child may have to wait for something, and the scheduler does not guarantee fair distribution of resources. Maybe the creation of a child process takes some time, so the parent may reach

    write(stdOut, "b\n", 2);
    

    before the child reaches

    write(stdOut, "a\n", 2);