1

I've written the code below. The parent process writes one character at a time, followed by a sleep call. The child process reads one byte at a time and prints it immediately after reading.

However, I get all the output at once after waiting several seconds when I run this. I expected to get one character per second. Why is this?

(I know I could write the string all at once, but this is an experiment for the future.)

int fd[2];
pipe(fd);

pid_t pid = fork();
if (pid == 0) {
    close(fd[WRITE_END]);
    char *read_msg;
    printf("Read: ");

    // Read characters.
    while (read(fd[READ_END], read_msg, 1)) {
        printf("%c", *read_msg);
    }

    printf("\n");
    close(fd[READ_END]);
} else {
    close(fd[READ_END]);
    char *msg = "Hello!";
    char *c = msg;

    // Write a character from parent every second.
    while (*c) {
        write(fd[WRITE_END], c++, 1);
        sleep(1);
    }

    close(fd[WRITE_END]);
    wait();
}
Emily Horsman
  • 195
  • 1
  • 7
  • 1
    You're calling `read`, passing the pointer `read_msg`. But *where does `read_msg` point?* – Some programmer dude Jan 13 '18 at 21:40
  • It seems odd to mix `read` and `printf`, and the buffered prints are the source of your confusion. Instead of `printf`, use `write` in the child. – William Pursell Jan 13 '18 at 21:48
  • @WilliamPursell Since `read` and `printf` are used with different files, it is okay to mix them. –  Jan 13 '18 at 21:50
  • @Ivan It's "okay" in one sense to mix them, but still odd. They certainly should not be mixed unless their use is well understood. – William Pursell Jan 13 '18 at 21:51
  • Ah that makes sense Some programmer dude, it's interesting that it still works, I guess it could be clobbering over something else. – Emily Horsman Jan 13 '18 at 21:54
  • @WilliamPursell `printf` is used for formatted output, but data receiving from the pipe can be binary. Also multiple parts of the program can already be writing something to `stdout` using `printf` and other functions. I would say using `write` and `read` with `stdout` at this point is _always_ a bad idea. –  Jan 13 '18 at 21:54

2 Answers2

1

You are using printf to print receiving characters. printf writers data to a FILE object which represents bufferred file. It avoids writing data to the actual file until some condition is met (or enough data was gathered) for performance reasons. When exactly data can flushed is described here: http://en.cppreference.com/w/cpp/io/c/setvbuf

Output of your program is most likely "line buffered", so data is actually written to the terminal on every new line character.

To avoid this you want to flush data manually after every received character using fflush. Another way is to change buffering policy using setvbuf.

You want something like this:

char c;
while (read(fd[READ_END], &c, 1) > 0) {
    printf("%c", c);
    fflush(stdout);
}

Notice that you should also read data into a char object.

  • There is a question about line buffering with a good answer: https://stackoverflow.com/questions/34806490/how-is-line-buffering-implemented-for-c-stdio-input-streams –  Jan 13 '18 at 21:41
1

printf by default uses a buffered file, it automatically flushes on '\n' or if you call fflush(stdout);

So just flush after your read in your loop.

Maeve Kennedy
  • 239
  • 1
  • 4
  • 11