Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Loop doesn't finish when reading from pipe

I’m following the free book Operating Systems: Three Easy Pieces by Arpaci-Dusseau, and despite being very new to C programming (constructive criticism is welcomed), I tried my luck on coding problem 8 from chapter 5:

Write a program that creates two children, and connects the standard
output of one to the standard input of the other, using the pipe()
system call.

Here is my attempt (some error-checking is removed for brevity):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

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

    pipe(pipefd);

    int rc1 = fork();
    if (rc1 == 0) {
        // Child 1, reading from argv, writing to pipe
        close(pipefd[0]);
        write(pipefd[1], argv[1], strlen(argv[1]));
        close(pipefd[1]);
        printf("Child 1 done.\n");
    } else {
        // Parent
        wait(NULL);
        int rc2 = fork();
        if (rc2 == 0) {
            // Child 2, reading from pipe, writing to stdout
            printf("Entering child 2\n");
            close(pipefd[1]);
            while (read(pipefd[0], &buf, 1) > 0) {
                write(STDOUT_FILENO, &buf, 1);
            }
            write(STDOUT_FILENO, "\n", 1);
            printf("Wrote to stdout!\n");
            close(pipefd[0]);
            printf("Child 2 done.\n");
        } else {
            // Still parent
            wait(NULL);
            printf("Parent finished running.\n");
        }
    }
}

which generates the following output, and hangs:

$ ./myprogram "Hello world"
Child 1 done.
Entering child 2
Hello world█

where is the shell cursor, i.e. the while loop hasn’t exited to reach the writing of the newline character thereafter.

I did, however, get this to work by replacing char buf; with char buf[1024]; and the lines

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

with

int n = read(pipefd[0], &buf, 1024);
write(STDOUT_FILENO, &buf, n);

So, now it works. But I don’t understand why the previous version did not work. That reading loop was practically identical to the one used in the example at the bottom of the pipe(2) man-pages, which I have verified to be working correctly for me. But why doesn’t it work in my own little program?

Possible duplicate questions:
(1) Solution is to close unused ends of pipe. I believe I have done that correctly.
(2) Solution is to break on return codes <= 0, not on < 0. I believe I have done that correctly too.

>Solution :

pipefd[1]) never gets closed in the original parent process. So read(pipefd[0], &buf, 1) will hang in the second child process.

This version

int n = read(pipefd[0], &buf, 1024);
write(STDOUT_FILENO, &buf, n);

doesn’t hang because there’s no loop. The second child process reads the data written by

write(pipefd[1], argv[1], strlen(argv[1]));

and then continues onward, never checking pipefd[0] again. So it doesn’t matter if read(pipefd[0],...) would hang.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading