Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks, I hope you can help me. The code below spawns off child processes and things are done at the child level. My first attempt was to have the child pass back variables to the parent, but that didn't go so well. I think this is (have the child do everything) the best way to handle it. But just for learning purposes how do I retain variables after the child exit? Thanks in advance.
#!/usr/bin/perl -W use scr_rsh; my @properties = ("run","conf"); my $cmd_run = "ps -ef|grep newmatch | grep \" 1 \"|wc -l"; my $cmd_conf = "wc -l /usr/local/multiplex.conf"; my ($pid,@pid); my $passwd = ask; print "\n"; # hash of hashes our $domatch = {}; # Hash of Hashes # set default values of HoH for(my $key1 = 0; $key1 <= $#ARGV; $key1++) { foreach my $key2 (@properties) { my $domatch = { $ARGV[$key1 ] => {$key2=>'0'} }; } } # Fork processes for($key1=0, $i = 1; ($i <= 2) && ($key1 <= $#ARGV); $i++,$key1++) { $pid=fork(); push @pids, $pid; if($pid == 0) { #Child Process $domatch->{$ARGV[$key1]}->{"conf"} = &get_proc_run($p +asswd,$ARGV[$key1]); $domatch->{$ARGV[$key1]}->{"run"} = &get_proc_conf($p +asswd,$ARGV[$key1]); &prt_result($ARGV[$key1]); exit(0); } if("$i" == "2") { $i=0; } } foreach my $childpid (@pids) { waitpid($childpid,0); } #-------------------------------------------- # Beging Sub-Routines #-------------------------------------------- sub prt_result { my $host = shift; if( $domatch->{$host}->{run} eq $domatch->{$host}->{conf} ) { print "$host green: $domatch->{ $host }->{conf}/$domat +ch->{ $host }->{run}\n"; } else { print "$host red: $domatch->{ $host }->{conf}/$domatch +->{ $host }->{run}\n"; } } sub get_proc_conf { my $passwd = shift; my $host = shift; # Get number of newmatch configured to be run on each server my $line = scr_remote("$passwd", "$cmd_conf", "$host"); chomp($line); my($junk,$wc) = split(/\s+/,$line); $wc =~ s/\s//g; # string spaces in a string #$domatch->{$host}->{"conf"} = "$wc"; return $wc; }sub get_proc_run { my $passwd = shift; my $host = shift; # Get PPID of newmatch only my $line = scr_remote("$passwd", "$cmd_run", "$host"); chomp($line); $line =~ s/\s//g; # string spaces in a string #$domatch->{$host}->{"run"} = "$line"; return $line; }

Edit kudra, 2001-11-23 Added additional desc to title

Replies are listed 'Best First'.
Re: forking: retaining variables after the child exits
by tadman (Prior) on Nov 23, 2001 at 22:02 UTC
    The only thing you can "return" from a child process is an exit code, which is simply the value sent from your exit call, but even then, you have to match this number up with the process in your signal handler, and so forth, so it's not very practical at all.

    You will certainly want to read the perlipc documents, those that deal with Inter-Process Communication. This is a fairly in-depth document, which can be confusing, but there are some good examples.

    Since the parent and the child are separate processes, they can't communicate with eachother through variables, like you can within a single program. Instead, you have to create some sort of mechanism for communication explicitly. Generally, this involves creating a pipe that is shared the parent and child. This data conduit is used by the child to send any required data back to the parent.

    Basically, the parent creates a pipe, which is double-ended, and then forks. The child will use one end of the pipe to report, and the parent will use the other end to listen. It's kind of like a tin-can and string telephone.

    Of course, the parent must check on these sockets for each child that is active. You can use select, or, if you're feeling rather spirited, IO::Select may be more to your liking since it is simpler. The idea is that while each child has a single end, the parent is going to have a whole lot of ends to check on, as data could come in at any time. IO::Select will let you know when something comes in on one of them.

    There is a good example of creating the pipe in the section of perlipc entitled "Bidirectional Communication with Yourself". There

    A simpler approach, which is more of a hack, really, is to just save some data in a temp file (i.e. "/tmp/$$.progname") and have the parent pick it up when the child is done. I would certainly have a go with the pipes before taking these comparatively drastic measures, though.
      If you're on a *nix platform, "shared memory" is an additional way that a child can communicate with a parent. This is definitely the "road less travelled," since shared memory isn't available on all platforms.

      Look in perlman:perlipc for the section on "SysV IPC". You'll find a short example, which might be enough to get you started.

      A number of folks recommend IPC::Shareable, with which I have no experience.

      It sounds like the question comes from someone accustomed to an environment with threads, such as java. It might make sense to look at Thread.

      One small trick I'd add to the comments about IPC is that one can use the Data::Dumper or other persistence modules to pass the datastructures you've built up over a pipe, or in a file.