5

I want to make a pipe between a child-writer and a parent-reader in C. I thought that my parent process would have to wait for its child to write in the buffer before being able to read it, but then I wanted to check it so I wrote the following piece of code:

pipe(fd);
// ... checks for pipe
pid_t pid = fork();
// ... checks for fork
if (pid == 0) {
    close(fd[0]);
    // Long sleep hoping parent will terminate before the write()
    sleep(10);
    write(fd[1], "hello", strlen("hello") + 1);
    close(fd[1]);
} else {
    close(fd[1]);
    read(fd[0], buf, sizeof(buf));
    printf("received: %s\n", buf);
    close(fd[0]);
}
return 0;

The output is unexpectedly (or is it not?) received: hello. Same output if I replace the call to sleep() by a for (volatile int i = 0; i < some_big_int; ++i); loop. I do not think that the call to read() will block my parent process until child writes at the other end of the pipe, but I cannot explain this behaviour though. Any hint?

hdl
  • 1,028
  • 1
  • 9
  • 23
  • 1
    this is the expected operation: I.E. `read()` blocks, will return on total bytes requested are read or eof is encountered. Or certain error events and signals – user3629249 Oct 05 '15 at 22:11
  • I cannot find where this is said in `man 2 read`: e.g. this sentence seems to indicate that if there is nothing to read, read() returns and is non-blocking : `In the absence of any errors, or if read() does not check for errors, a read() with a count of 0 returns zero and has no other effects.` – hdl Oct 05 '15 at 22:22
  • 1
    When `read` is passed a non-zero `count` on a streaming fd (e.g. a pipe), it blocks until at least 1 byte is available, then reads as much of `count` as it can at that time. Since you `write` and `close` (and the write is smaller than `PIPE_BUF`), it's flushing the whole string at once, so when it unblocks, it gets all of what you wrote at once. – ShadowRanger Oct 05 '15 at 22:33
  • The bit about `read` with a `count` of 0 is irrelevant to your situation, because you didn't pass a `count` of 0. – ShadowRanger Oct 05 '15 at 22:34
  • 1
    `write(fd[1], "hello", strlen("hello"));` and `read(fd[0], buf, sizeof(buf));` will not NUL-terminate buf, as the terminating NUL is not written to the pipe. Also, `printf("received: %s\n", buffer);` prints the output of `buffer`, not the contents of `buf`. Were it to try to print the contents of `buf`, the code posted would invoke undefined behavior. Additionally, a failed `fork()` call will result in the parent process blocking forever in `read()`. – Andrew Henle Oct 05 '15 at 22:38
  • perhaps the answers/comments at: would be helpful – user3629249 Oct 05 '15 at 22:39

1 Answers1

6

read will block until there is at least one byte to read, or it encounters an error, or it reaches the end of the stream. When there is at least one byte to read, it will read as many bytes as it can (up to the maximum number you specify) and then return.

In this case, the parent process's call to read will block until the child process writes something to the pipe.


From man 7 pipe section I/O on pipes and FIFOs :

If a process attempts to read from an empty pipe, then read(2) will block until data is available. If a process attempts to write to a full pipe (see below), then write(2) blocks until sufficient data has been read from the pipe to allow the write to complete. Nonblocking I/O is possible by using the fcntl(2) F_SETFL operation to enable the O_NONBLOCK open file status flag.

hdl
  • 1,028
  • 1
  • 9
  • 23
user253751
  • 57,427
  • 7
  • 48
  • 90
  • Where is this specified? Unfortunately I id not find this information in either `man 2 pipe` nor `man 2 read` – hdl Oct 06 '15 at 13:14
  • 1
    Found it in `man 7 pipe`, and edited your answer accordingly. Thank you very much. – hdl Oct 06 '15 at 13:17