The following code runs 2 children, who will wait for 10 seconds and terminate. The parent is sitting in a loop, waiting for the children to terminate:
#!/usr/bin/perl
use strict;
use warnings;
use POSIX ":sys_wait_h";
sub func
# {{{
{
my $i = shift;
print "$i started\n";
$| = 1;
sleep(10);
print "$i finished\n";
}
# }}}
my $n = 2;
my @children_pids;
for (my $i = 0; $i < $n; $i++) {
if ((my $pid = fork()) == 0) {
func($i);
exit(0);
} else {
$children_pids[$i] = $pid;
}
}
my $stillWaiting;
do {
$stillWaiting = 0;
for (my $i = 0; $i < $n; ++$i) {
if ($children_pids[$i] > 0)
{
if (waitpid($children_pids[$i], WNOHANG) != 0) {
# Child is done
print "child done\n";
$children_pids[$i] = 0;
} else {
# Still waiting on this child
#print "waiting\n";
$stillWaiting = 1;
}
}
#Give up timeslice and prevent hard loop: this may not work on all flavors of Unix
sleep(0);
}
} while ($stillWaiting);
print "parent finished\n";
The code is based upon this answer: Multiple fork() Concurrency
It works correctly, but the parent loop is eating processor time. top
command gives this:
Here the answer says:
As an additional bonus, the loop will block on
waitpid
while children are running, so you don't need a busy loop while you wait.
But for me it doesn't block. What's wrong?
You're passing the WNOHANG
flag, which makes the call non-blocking. Remove this flag and waitpid
will wait at 0% CPU until the child quits.
If you take this approach, you could simplify the code. There's no need to loop until a child is finished, because the blocking waitpid
call will do that for you:
for (my $i = 0; $i < $n; ++$i) {
if ($children_pids[$i] > 0) {
waitpid($children_pids[$i], 0);
print "child done\n";
$children_pids[$i] = 0;
}
}
Alternatively, change the sleep
call to wait for one second. Then your program will check for finished children every second, without pushing up CPU usage.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With