Child processes don't get the close on pipe



Hi,

I have a problem with pipes that I do not understand at all. My code
forks a number of child processes, and creates a pipe for every one of
them. The parent then writes data to the child's pipes, finishing the
whole process by closing the pipe.

The children consume to data and write results back to the parent
through the other side of the pipe. The problem is that the children
do not get an EOF on the pipes and expect more data, resulting in a
deadlock. I can't see what the problem with my code could be and
therefore extracted the relevant parts into the script pasted below
(you can also find it at pastebin: http://pastebin.com/KarksDXf )

Can someone point me to the problematic parts of the code?

#!/usr/bin/env perl -w

use strict;
use POSIX;

my $num_processes = 2;
my %process_data;

sub worker_thread {
my $id = shift;
my $reader = shift;
my $writer = shift;

print STDERR "Child $id: Starting to consume input ...\n";
while(<$reader>) {
chomp;
print STDERR "$id: Got line \"$_\"\"\n";
}

print STDERR "Finished consuming packets ...";
print $writer "$id: this is my result\n";
}

sub parent_reader {
for (0 .. $num_processes - 1) {
my $writer = ${$process_data{$_}}[1];
print $writer "Got some work\n";
}
}
################ main

# start the worker processes
for my $pnum (0 .. $num_processes - 1) {
print $pnum, "\n";
local *READER;
local *WRITER;
pipe(*READER, *WRITER);
my $pid = fork();
if (defined $pid && $pid == 0) {
worker_thread($pnum, *READER, *WRITER);
exit -1;
} elsif (defined $pid && $pid > 0) {
$process_data{$pnum} = [ *READER, *WRITER, $pnum];
}
}

# run the main reader loop, and pass data to the readers
parent_reader();

print "Parent: Finished reading input data from stdin...\n";

# close the pipes to indicate that there will be no more data
for my $i (keys %process_data) {
my $writer = $process_data{$i}[1];
print scalar $writer, "\n";
close($writer) or warn "Error closing pipe: $!";
}

# collect the results
for my $i (keys %process_data) {
my $reader = ${process_data{$i}}[0];
while (<$reader>) {
print "$_";
}
}

# wait for child processes to end
for my $i (keys %process_data) {
my $ret = waitpid(-1, 0);

if ($ret<0 || $ret>0) {
print "process $ret finished..\n";
delete $process_data{$ret};
}
}

.



Relevant Pages

  • Re: IPC
    ... Ich hab mich entschieden das über pipes zu machen.... ... pipe my ($reader, $writer); ... store_fd \%$chld_searchentries, $writer; ... um die Daten hinter der Referenz zu deserialisieren und auf der ...
    (de.comp.lang.perl.misc)
  • Re: Clueless: piping between 2 non-python processes
    ... ideally you'd close all other file descriptors in the child process ... Well, if these are the only child processes his program spawns, he can ... > brittle, because pipes have a fixed, limited buffer size and because ... to call fflushor change their I/O library's buffer settings as needed. ...
    (comp.lang.python)
  • Re: Clueless: piping between 2 non-python processes
    ... that's more to avoid keeping a file ... UNIX file descriptors are ... | Well, if these are the only child processes his program spawns, he can ... | If buffering is a problem, the processes comminicating via pipes are welcome ...
    (comp.lang.python)
  • Re: kill or pipe
    ... child processes and among child processes? ... With kill, you can signal the parent's whole process group in one fell ... required pipes open and then decide which ones and directions they can ... This gives info on using combinations of signals, ...
    (comp.unix.bsd.freebsd.misc)
  • Re: Child processes dont get the close on pipe
    ... I have a problem with pipes that I do not understand at all. ... my $reader = shift; ... local *WRITER; ... Since the child inherits the 'writer' handle but doesn't close ...
    (comp.lang.perl.misc)