# 本程序主要利用PIPE来建立Parent Process与Child Process间的互相连通,
# 利用%STATUS纪录目前Child Process的所有状态,与%CHILDREN纪录所有的Child
# Process。
# Parent Process:负责由CHILD_READ中读取所有CHILD Process的输入,并纪录
# 这些Process目前的状态。当收到INT、HUP、TERM等Signal时,即跳出主要loop
# 并将所有child Process全部杀光...
# 利用%STATUS纪录目前Child Process的所有状态,与%CHILDREN纪录所有的Child
# Process。
# Parent Process:负责由CHILD_READ中读取所有CHILD Process的输入,并纪录
# 这些Process目前的状态。当收到INT、HUP、TERM等Signal时,即跳出主要loop
# 并将所有child Process全部杀光...
代码: |
#!/usr/bin/perl use strict; use IO::Select; use POSIX qw(WNOHANG); #---Define constants:定义准备先fork几个Process use constant PREFORK_CHILDREN => 3; # debugging information:显示过程 use constant DEBUG => 1; # declare globals my $DONE=0; # set flag to true when server done my %STATUS = (); #child status information, child pid form keys of the ha sh, status form the values #--- 纪录所有Child Process的id... my %CHILDREN = (); #---Interrupt handles,跳出loop $SIG{TERM} = $SIG{INT}=$SIG{HUP} = sub { $DONE++ }; #--- get CHLD Signal $SIG{CHLD} = sub { while((my $child=waitpid(-1,WNOHANG)) > 0){ delete $CHILDREN{$child}; } }; # create a pipe for IPC:建立PIPE pipe(CHILD_READ,CHILD_WRITE) or die "Can't make pipe!/n"; my $IN = IO::Select->new(/*CHILD_READ); # prefork some children make_new_child() for (1..PREFORK_CHILDREN); # main loop while(!$DONE){ # avoid parent block in the I/O call if ($IN->can_read){ # got a message from one of the children my $message; next unless sysread(CHILD_READ,$message,4096); # may contain several messages my @messages = split "/n",$message; # retrive every pid and status code foreach (@messages){ next unless my ($pid,$status) = /^(/d+) (.+)$/; # change status if($status ne "done"){ $STATUS{$pid} = $status; }else{ # delete pid delete $STATUS{$pid}; } } } warn join(' ',map {"$_=>$STATUS{$_}"} keys %STATUS),"/n" if DEBUG; last unless %CHILDREN } warn "Termination received, killing children/n" if DEBUG; #-------------杀掉所有Child Process kill TERM => keys %CHILDREN; sleep while %CHILDREN; warn "Normal termination./n"; exit 0; #---- 建立新的Process sub make_new_child{ die "can't fork :$!" unless(defined( my $child = fork())); if($child){ # child > 0, so we're the parent $CHILDREN{$child} = 1; warn "launching child $child/n" if DEBUG; }else{ close CHILD_READ; # no need to read from pipe do_child(); # child handles incoming connections exit 0; # child is done } } #------ child process sub do_child{ # write status code: idle syswrite CHILD_WRITE,"$$ idle/n"; for(1..1000000){ }; syswrite CHILD_WRITE,"$$ busy/n"; for(1..1000000){ }; syswrite CHILD_WRITE,"$$ done/n"; } |