Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't my parent process see the child's output until it exits?

Tags:

perl

ipc

Consider the following script:

use IO::File;
$| = 1;
my ($handle, $pid) = myPipe();
if ($pid == 0) {
  print "$$";
  sleep 5;
  exit;
}

print "child: ".<$handle>."\n";

sub myPipe {
  my $handle = new IO::File();
  my $pid = open($handle, "-|");
  return ($handle, $pid);
}

In this case, the "child:" message doesn't appear for 5 seconds after the process starts. If I remove the sleep call from the forked child, then it prints immediately. Why does the forked child have to exit for the pipe to flush to the parent?

like image 555
dromodel Avatar asked Feb 26 '10 17:02

dromodel


2 Answers

There are two issues. First, the child process is buffering its output; and second, the parent process is using the <> operator, which blocks until a complete line is available, or until end-of-file.

So, one way to get the result you were expecting is to have the child process close its output stream immediately after writing:

if ($pid == 0) {
    print "$$";
    close STDOUT;
    sleep 5;
    exit;
}

Another way is to add a newline to the child process's output, then flush the stream:

if ($pid == 0) {
    print "$$\n";
    STDOUT->flush;  # "close STDOUT;" will work too, of course
    sleep 5;
    exit;
}

The flush is necessary because pipes are (typically) unbuffered, rather than line-buffered as streams connected to the terminal usually are.

A third alternative is to set the child process's output stream to autoflush:

if ($pid == 0) {
    $| = 1;
    print "$$\n";
    sleep 5;
    exit;
}
like image 77
Sean Avatar answered Jun 08 '23 18:06

Sean


On some (most?) systems, pipes use I/O buffering by default. Put a

$handle->autoflush(1);

statement in your myPipe function.

But even when buffering is turned off, Perl still doesn't flush except after a newline. So you may also want your child process to include a newline in the output.


Update: Testing your code (Cygwin, perl 5.10.0, YMMV), I see the issue is a lack of the newline in the child output, not whether autoflush is explicitly turned on when the pipe is created.

like image 31
mob Avatar answered Jun 08 '23 19:06

mob