eval { $var = #setup a network connection...; $SIG{ALRM} = sub { flock $fh, LOCK_EX; print $fh "\n"; flock $fh, LOCK_UN;}; alarm(60); }; #### use strict; use warnings; use Fcntl qw(:flock); use File::Copy 'move'; use POSIX "sys_wait_h"; #for waitpid FLAGS use Time::Local; $|=1; my @child_sleeps = qw(10 15 12 5 12); my $start_epoch = time(); # Fire off number of child processes equal to the # number of elements in @child_sleeps; # Then the parent who started these little guys, # goes into a blocking wait until they all finish # Each child can return a status code via exit($code_number). # However, this code doesn't use that and instead assumes # that children and the parent are all writing to a common # file shared via a cooperative flock $SIG{CHLD} = 'IGNORE'; open(my $fh_log, '>>', "Alogfile.txt") or die "unable to open Alogfile.txt $!"; #$fh_log->autoflush; #not needed this is automatic before locking or unlocking a file! foreach my $sleep_interval (@child_sleeps) { if(my $pid = fork) { # parent safe_print ($fh_log, "Spawned child $pid lasting $sleep_interval seconds\n"); } elsif(defined $pid ) # pid==0 { # child safe_print ($fh_log, "This is child pid $$. I will sleep for $sleep_interval seconds!\n"); sleep($sleep_interval); safe_print ($fh_log, "Child $$ time is up!! I am gonna croak!\n"); exit(0); } else { # fork failed pid undefined die "MASSIVE ERROR - FORK FAILED with $!"; } } ### now wait for all children to finish, no matter who they are 1 while wait != -1 ; # avoid zombies this is a blocking operation safe_print ($fh_log, "Parenting talking...all my children are dead! Hooray!\n"); close $fh_log; #must close file before renaming it! unlink "Alogfile.back" if ( -e "Alogfile.back"); move "AlogFile.txt", "AlogFile.back" or die "unable to rename log file! $!"; print "A happy ending!\n"; sub safe_print { my ($fh, @text) = @_; my $now_epoch = time(); my $delta_secs = $now_epoch - $start_epoch; flock $fh, LOCK_EX or die "flock can't get lock $!"; print $fh "$delta_secs secs: $_" foreach @text; print "$delta_secs secs: $_" foreach @text; flock $fh, LOCK_UN or die "flock can't release lock $!"; } __END__ Contents of AlogFile.back after a run: 0 secs: Spawned child -10680 lasting 10 seconds 0 secs: This is child pid -10680. I will sleep for 10 seconds! 0 secs: Spawned child -23840 lasting 15 seconds 0 secs: This is child pid -23840. I will sleep for 15 seconds! 0 secs: Spawned child -14556 lasting 12 seconds 0 secs: This is child pid -14556. I will sleep for 12 seconds! 0 secs: Spawned child -13972 lasting 5 seconds 0 secs: This is child pid -13972. I will sleep for 5 seconds! 0 secs: Spawned child -18600 lasting 12 seconds 0 secs: This is child pid -18600. I will sleep for 12 seconds! 5 secs: Child -13972 time is up!! I am gonna croak! 10 secs: Child -10680 time is up!! I am gonna croak! 12 secs: Child -14556 time is up!! I am gonna croak! 12 secs: Child -18600 time is up!! I am gonna croak! 15 secs: Child -23840 time is up!! I am gonna croak! 15 secs: Parenting talking...all my children are dead! Hooray! A happy ending! #### use strict; use warnings; use Fcntl qw(:flock); use File::Copy 'move'; use POSIX "sys_wait_h"; #for waitpid FLAGS my @child_sleeps = qw(10 15 12 5 12); # Fire off number of child processes equal to the # number of elements in @child_sleeps; # Then the parent who started these little guys, # goes into a blocking wait until they all finish # Each child can return a status code via exit($code_number). # However, this code doesn't use that and instead assumes # that children and the parent are all writing to a common # file shared via a cooperative flock $SIG{CHLD} = 'IGNORE'; open(my $fh_log, '>>', "Alogfile.txt") or die "unable to open Alogfile.txt $!"; #$fh_log->autoflush; #not needed this is automatic before locking or unlocking a file! foreach my $sleep_interval (@child_sleeps) { if(my $pid = fork) { # parent safe_print ($fh_log, "Spawned child $pid lasting $sleep_interval seconds\n"); } elsif(defined $pid ) # pid==0 { # child safe_print ($fh_log, "This is child pid $$. I will sleep for $sleep_interval seconds!\n"); sleep($sleep_interval); safe_print ($fh_log, "Child $$ time is up!! I am gonna croak!\n"); exit(0); } else { # fork failed pid undefined die "MASSIVE ERROR - FORK FAILED with $!"; } } ### now wait for all children to finish, no matter who they are 1 while wait != -1 ; # avoid zombies this is a blocking operation close $fh_log; #must close file before renaming it! unlink "Alogfile.back" if ( -e "Alogfile.back"); move "AlogFile.txt", "AlogFile.back" or die "unable to rename log file! $!"; print "A happy ending!\n"; sub safe_print { my ($fh, @text) = @_; flock $fh, LOCK_EX or die "flock can't get lock $!"; print $fh @text; flock $fh, LOCK_UN or die "flock can't release lock $!"; } __END__ Results from testing on Windows (they use a negative PID for their fork emulation) Spawned child -20688 lasting 10 seconds This is child pid -20688. I will sleep for 10 seconds! Spawned child -19896 lasting 15 seconds This is child pid -19896. I will sleep for 15 seconds! Spawned child -24392 lasting 12 seconds This is child pid -24392. I will sleep for 12 seconds! Spawned child -24692 lasting 5 seconds This is child pid -24692. I will sleep for 5 seconds! Spawned child -20296 lasting 12 seconds This is child pid -20296. I will sleep for 12 seconds! Child -24692 time is up!! I am gonna croak! Child -20688 time is up!! I am gonna croak! Child -24392 time is up!! I am gonna croak! Child -20296 time is up!! I am gonna croak! Child -19896 time is up!! I am gonna croak!