0

The following code redirects stdout to the write-end of a pipe, whose read-end I then read from.

// main.cpp
#include <cassert>
#include <iostream>
#include <unistd.h>

int main( int argc, char* argv[] ) {
  int my_pipe[2] = { -1, -1 };
  char buf[100] = { '\0' };
  int stdout_copy;

  assert( -1 != (stdout_copy = dup( STDOUT_FILENO )) );
  assert( 0 == pipe( my_pipe ) );
  assert( -1 != dup2( my_pipe[1], STDOUT_FILENO ) );
  //close( my_pipe[1] );    // (1) Uncommenting this prevents hang.
  //my_pipe[1] = -1;

  std::cout << "hello"
            //<< std::endl  // (2) Uncommenting this also prevents hang.
            ;

  assert( -1 != dup2( stdout_copy, STDOUT_FILENO ) );

  read( my_pipe[0], buf, sizeof buf );
  std::cout << buf;

  close( my_pipe[0] );

  return 0;
}
$ g++ --version && g++ -g ./main.cpp
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

Toying around with this code, I noticed that the read hangs unless I either (1) close my pipe's write-end after dup2ing STDOUT_FILENO to it, and/or (2) explicitly writing a std::endl to std::cout. Why is this so?

At first, I thought the issue had something to do with flushing of stdout - which might've explained the need to explicitly write std::endl, but (per my perhaps incomplete understanding) that doesn't explain why closing the write-end of the pipe would prevent the hang.


Update: I found this interesting: when both (1) and (2) are commented, std::cout << "hello\n"; does not prevent the hang; i.e. it's not "equivalent" to std::cout << "hello" << std::endl;.

StoneThrow
  • 5,314
  • 4
  • 44
  • 86
  • `std::endl` does two things: it outputs `\n` to the stream, and it calls `flush()` on it. The latter is the important part in your case. Until `flush()` call, the stream buffers the characters in memory and doesn't write them to the underlying file handle. Closing the stream also flushes any buffered characters. – Igor Tandetnik Jan 02 '21 at 05:00
  • When you close the write end right after `dup2`, `read` doesn't hang - but does it actually read `"hello"`? I suspect it simply encounters end-of-file right away and doesn't read anything. – Igor Tandetnik Jan 02 '21 at 05:18
  • @IgorTandetnik - RE: second question, yes, when I close file descriptor (comment (1)), then `read` does actually read the `"hello"`. – StoneThrow Jan 04 '21 at 22:11

0 Answers0