Non-blocking waiting, rerun on failure


In this example we have a list of tasks we need to do. The user can supply the number of child processes that will deal with the tasks. Each child process generates a random number to wait to imitatet the work time and a random number as the exit code.

The parent monitors the child processes. If one of them exits with a non-zero error code the parent re-runs that job with another child process until all the tasks are done.


examples/forks/active_waiting_tasks.pl
use strict;
use warnings;
use Time::HiRes qw(sleep);
use POSIX ':sys_wait_h';

main();

sub main {
    my ($workers) = @ARGV;
    die "Usage: $0 WORKERS\n" if not defined $workers;
    #my @tasks = 'a' .. 'z';
    my @tasks = 'a' .. 'd';

    my %process;
    while (1) {
        if (@tasks and scalar(keys %process) < $workers) {
            my $task = shift @tasks;

            my $pid = fork();
            die 'Failed to fork' if not defined $pid;

            if ($pid == 0) {
                my $exit_code = int rand(3);
                my $sleep_time = rand(5);
                print "Child process Task: $task PID $$ will sleep for $sleep_time and then exit with code $exit_code\n";
                sleep $sleep_time;
                exit $exit_code;
            }
            $process{$pid} = $task;
            next;
        }

        my $pid = waitpid(-1, WNOHANG);
        if ($pid > 0) {
            my $exit_code = $?/256;
            my $task = delete $process{$pid};
            print "Child process $pid task $task finished with exit code $exit_code\n";
            if ($exit_code > 0) {
                unshift @tasks, $task;
            }
            next;
        }
        sleep 0.1;
        last if not %process;
    }
}

Child process Task: a PID 128387 will sleep for 3.71995377981634 and then exit with code 2
Child process Task: b PID 128388 will sleep for 0.137503658640838 and then exit with code 0
Child process Task: c PID 128389 will sleep for 3.57264931009681 and then exit with code 1
Child process 128388 task b finished with exit code 0
Child process Task: d PID 128390 will sleep for 0.940422063447244 and then exit with code 0
Child process 128390 task d finished with exit code 0
Child process 128387 task a finished with exit code 2
Child process 128389 task c finished with exit code 1
Child process Task: a PID 128391 will sleep for 3.09917882712156 and then exit with code 2
Child process Task: c PID 128392 will sleep for 1.52811677938857 and then exit with code 2
Child process 128392 task c finished with exit code 2
Child process Task: c PID 128393 will sleep for 1.21268558593997 and then exit with code 0
Child process 128393 task c finished with exit code 0
Child process 128391 task a finished with exit code 2
Child process Task: a PID 128394 will sleep for 2.05004244389542 and then exit with code 2
Child process 128394 task a finished with exit code 2
Child process Task: a PID 128395 will sleep for 4.95541832222202 and then exit with code 0
Child process 128395 task a finished with exit code 0