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

Hi, I'm trying to pop elements from an array in parallel until it consumes everything, then have the forks return it back for the next consumers. I can't figure out why I keep on getting the uninitialized value error (below). I thought adding a sleep before the start() would help (I am probably misunderstanding the problem as forks being too fast) but it only helped to a certain extent (compared to not having a sleep at all).
#!/usr/bin/perl use strict; use warnings; use Parallel::ForkManager; my @keycards= qw(A B C); my @users = qw(peter james john luke andrew judas); my $pm = Parallel::ForkManager->new(3); $pm->run_on_finish( sub { my $key = $_[5]->{key}; unshift(@keycards, $key); } ); foreach my $user (@users) { sleep(int(rand(3))); my $key = pop(@keycards); $pm->start and next; print "$user took the '$key' key\n"; $pm->finish(0, { key => $key }); } $pm->wait_all_children;
[user@localhost ~/bin]$ perl a.pl peter took the 'C' key james took the 'B' key john took the 'A' key luke took the 'C' key andrew took the 'B' key judas took the 'A' key [user@localhost ~/bin]$ perl a.pl peter took the 'C' key james took the 'B' key john took the 'A' key Use of uninitialized value in concatenation (.) or string at a.pl line + 23. luke took the '' key andrew took the 'C' key judas took the 'B' key

Replies are listed 'Best First'.
Re: Parallel::ForkManager and stack
by Anonymous Monk on Jan 27, 2016 at 10:32 UTC
    my @keycards= qw(A B C); my @users = qw(peter james john luke andrew judas); ... foreach my $user (@users) { sleep(int(rand(3))); my $key = pop(@keycards); $pm->start and next;
    as been said, it's a race condition.
    1. peter pops keycard and starts
    2. james pops keycard and starts
    3. john pops keycard and starts
    4. luke pops keycards. It starts if one (or more) of peter, james or john has already finished. Otherwise it waits for one of them to quit. But what kind of keycard does it have?
    Fixing the problems with forks (or threads) by randomly inserting calls to sleep is a TERRIBLE idea. Just don't ever do it!

    It seems to me this problem could be solved by

    my $pm = Parallel::ForkManager->new(2);
    or, more generally
    my $pm = Parallel::ForkManager->new(@keycards - 1);
    All in all, that looks like a fairly questionable, error-prone feature of Parallel::ForkManager (which is a good module otherwise).

      Better solution (since it allows all keycards to be in use at the same time):

      foreach my $user (@users) { $pm->wait_one_child() while !@keycards; <----- my $key = pop(@keycards); $pm->start and next; print "$user took the '$key' key\n"; $pm->finish(0, { key => $key }); } $pm->wait_all_children;
        thanks to both of you. I didn't know about wait_one_child(), (and only realized how to use wait_for_available_procs() after seeing your post). This solves my problem
Re: Parallel::ForkManager and stack
by Anonymous Monk on Jan 27, 2016 at 09:56 UTC
    forking isn't threads/forks, children cannot populate parents copy of @keycards
      bah, forkmanager feature, ... its a simple race condition, new child is forked before a keycard is back in the @keycards