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

in my pre-forking Daemon, I have parent process which monitoring the status of the forked child and fork new one whenever existing child is dead. there are also a IPC shareable var which holds epoch time value is shared between parent and child process.

I have 3 sample scripts.
1. preload.pl: init a ipc shareable variable $newvalue.
2. ipcprocesses.pm: ipcprocess perl module which is used by ipcprocess perl script.
3. ipcprocesses.pl: main script.

what I expect is that whenever a child is dead, parent will be notified and re-fork a new one which INHERITS the shareble variable from the parent. since the shareable variable will be updated quite often, so the new forked child should also inherits the most current value.

The problem I got is that: new forked child do not get the lastest value from shareable variable but only the inited value when parent start up.

by my investigation,it turned out whenever a child dead, parent did get notified by SIG ALARM from child and got the value from shared var, however ,new forked child did not get the value from it.

I pasted the 3 scripts below (sorry, a little bit long), please take a look for me and drop something if you have. thank you.

#!/usr/bin/perl -w #preload.pl use IPC::Shareable; my $newvalue; tie $newvalue,'IPC::Shareable','kali',{create => 1,size => 65536}; $newvalue=0;
#!/usr/bin/perl -w #ipcprocesses.pm. #you may find some of the variables are not defined here #that is fine for demo purpose. package ipcprocesses; use POSIX; use IPC::Shareable; my $newvalue; my $num_children = 0; sub new { my $class = shift; my $this = { 'field' => 1 }; bless ($this,$class); tie $newvalue,'IPC::Shareable','kali'; return ($this); } $SIG{CHLD} = \&DO_AirGREAPER; $SIG{INT} = $SIG{TERM} = \&DO_AirGStopHandler; $SIG{ALRM} = sub {}; sub DO_AirGStopHandler { local( $SIG{CHLD} ) = 'IGNORE'; kill 'INT' => keys %H_children; exit; } sub DO_AirGREAPER { # takes care of dead children my ( $N_pid ); # If a second child dies while in the signal handler #caused by the # first death, we won't get another signal. So must # loop here else # we will leave the unreaped child as a zombie. And the # next time # two children die we get another zombie. And so on. while ( ($N_pid = waitpid(-1, &WNOHANG)) > 0 ) { if (WIFEXITED $?){ $num_children--; } } $SIG{CHLD} = \&DO_AirGREAPER; } sub DO_Initprocesspool { my $this = shift; # Fork off our children. for ( 1 .. 2 ) { $this->DO_newchild(); } } sub DO_newchild { my $this = shift; if ($pid = fork) { #parent $this->{'field'} = $newvalue; $num_children++; print 'parent'.$$.'|'.$this->{'field'}."\n"; return; } else{ my $newvalue; tie $newvalue,"IPC::Shareable",'kali'; #Children can not return from this subroutine $SIG{INT} = 'DEFAULT'; #make SIGINT kill us as it did befo +re while(1) { sleep 2; print 'child'.$$.'|'.$this->{'field'}."\n"; $newvalue = time(); } } exit; } sub DO_MaintainPopulation { my $this = shift; for ( my $i = $num_children; $i < 2; $i++ ) { # top up the child pool $this->DO_newchild(); } } 1;
#!/usr/bin/perl -w #ipcprocesses.pl use strict; use lib qw (/somepath); use ipcprocesses; my $fork = ipcprocesses->new(); while ( 1 ) { $fork->DO_MaintainPopulation(); }

Edited by planetscape - added readmore tags and rudimentary formatting

( keep:0 edit:9 reap:0 )

Replies are listed 'Best First'.
Re: IPC and communication between Parent and Child Process
by shmem (Chancellor) on Oct 25, 2006 at 07:42 UTC
    What is the 'field' attribute of your object supposed to hold? It gets a copy of the tied variable $newvalue i.e. the content of that variable at the time of object creation, which you are masking and tying in an inner scope (in the child).

    #!/usr/bin/perl -w #ipcprocesses.pm. ... sub new { my $class = shift; my $this = { 'field' => 1 }; bless ($this,$class); tie $newvalue,'IPC::Shareable','kali'; return ($this); } ... sub DO_newchild { my $this = shift; ... if ($pid = fork) { #parent $this->{'field'} = $newvalue; ... } else{ my $newvalue; tie $newvalue,"IPC::Shareable",'kali';

    The $newvalue in DO_newchild masks the outer $newvalue.

    If you want the 'field' member to hold a tied variable, tie the value:

    sub new { my $class = shift; #my $this = { 'field' => 1 }; my $this = { }; bless ($this,$class); tie $this->{'field'},'IPC::Shareable','kali'; $this->{'field'} = 1; return ($this); } ... sub DO_newchild { my $this = shift; if ($pid = fork) { #parent # $this->{'field'} = $newvalue; $num_children++; print 'parent '.$$.' | '.$this->{'field'}."\n"; return; } else{ #my $newvalue; #tie $newvalue,"IPC::Shareable",'kali'; #Children can not return from this subroutine $SIG{INT} = 'DEFAULT'; #make SIGINT kill us as it did befo +re while(1) { sleep 2; print 'child '.$$.' | '.$this->{'field'}."\n"; #$newvalue = time(); $this->{'field'} = time; } } exit; }

    That's what you do if you want the 'field' object to be updatable by the parent and child processes, visible to each.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      thanks for the reply, field supposed to holds the latest value in share memory, $newvalue.

      what confused me is that when child process is dead, parent will fork a new one, at that time I do see field of the object in parent holds the latest value of $newvalue since this section get executed:

      if ($pid = fork) { #parent $this->{'field'} = $newvalue; $num_children++; print 'parent'.$$.'|'.$this->{'field'}."\n"; return; }
      so I expect the forked new child should also have that value.from my understanding of the fork, it will get a copy of the parent's var, filehandle,etc. right ? However, new child does not get the lastest $newvalue but get the value when parent first startup (parent never exit since this is a daemon which monitors child). so did I misunderstand the meaning of fork or something else ? btw, in the child section, I removed the tie $newvalue... so that $newvalue will always be the one in share memory.
        so I expect the forked new child should also have that value.
        No, it doesn't. While your assumptions about fork are correct (i.e. the child is a full copy of the parent) - the assignment $this->{'field'} = $newvalue is done after the fork happened, so it's visible at the next fork.

        At startup you get 2 child processes, one of them reports 0, the other reports 1.

        Why's that? One child has the value '1' in the 'field' member of the object, from the object constructor new(). The parent then (after having forked) assigns $newvalue - '0' - to the 'field' member, so at the next fork the value for 'field' is '0'.

        Since the 'field' member isn't a shared variable, it can't be set in the parent from the child.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}