2

I'm trying to work as an example for the following code:

    my $milon;
    my $pid = fork();
    die if not defined $pid;    
    if (not $pid) 
    {
        $milon->{$pid} = $pid;
        exit;
    }
    
    $milon->{3} = 4;        
    my $finished = wait();  
    print( "debug10: TEST = ", Dumper($milon));

output:

debug10: TEST = $VAR1 = {
          '3' => 4
        };

How do I make the dictionary keep both 3 => 4 and also the $pid => $pid? It doesn't have to be forking, it could be multithreading or NonBlocking IO, whichever is better according to what you think.

This is an example of course, I just want to conclude from this example to my real code.

Dada
  • 6,313
  • 7
  • 24
  • 43
urie
  • 361
  • 2
  • 14
  • I've edited out your first question (since each question is supposed to contain _one_ question). See [How do I control the variable names in Perl's Data::Dumper?](https://stackoverflow.com/questions/908741/how-do-i-control-the-variable-names-in-perls-datadumper) for the answer though. – Dada Aug 19 '21 at 10:02
  • Each process has its on memory. Changing the child's `%$milon` has no effect on the parent's `%$milon` – ikegami Aug 19 '21 at 17:29

2 Answers2

3

You need some memory that is shared between your threads/processes. The easiest is probably to use interpreter-based threads and threads::shared. For instance:

use threads;
use threads::shared;

my %milon :shared;

for (1 .. 2) {
    threads->create(sub {
        my $tid = threads->tid();
        $milon{$tid} = $tid;
    });
}

$milon{3} = 4;

$_->join for threads->list; # Wait for all threads to be done

print Dumper \%milon;

This outputs:

$VAR1 = {
          '1' => 1,
          '2' => 2,
          '3' => 4
        };
Dada
  • 6,313
  • 7
  • 24
  • 43
  • Hi, your example worked, but I would like to ask about a case of a pointer... Thanks means that I don't want to declare milon as %milon, but as $milon with milon->{value} etc. I did your exact code with the adjustments, but I got:Perl exited with active threads: 0 running and unjoined 2 finished and unjoined 0 running and detached – urie Aug 19 '21 at 13:21
  • @urie You need to manually `share` each hash or array that you want to share. If you want `$milon` to be a hash reference, then you can do `share(my $milon = {})` for instance. – Dada Aug 19 '21 at 13:28
  • @urie There is `shared_clone` for complex data structures. See an example [here](https://stackoverflow.com/a/46705209/4653379). – zdim Aug 19 '21 at 18:01
  • @urie Also note that threads and sharing data between them comes with subtleties. I suggest to study the documentation very carefully and to find and review good examples around here. – zdim Aug 19 '21 at 18:02
  • @Dada any ideas how can I use this code in case the values of the dictionary arrive of other variables? Is there a way to do that WITHOUT having to change everything to shared? – urie Aug 22 '21 at 08:40
1

Following sample code demonstrates usage of fork() to compute square of a number from an array @numbers (total 100) in parallel execution.

REAPER function assigned to $SIG{CHLD} signal cleans up completed child processes to avoid zombie processes hanging around in process table.

Investigate if fork() approach will fit your problem/task.

use strict;
use warnings;

use POSIX qw(strftime :sys_wait_h);
use Time::HiRes qw(usleep);

my $limit   = 10;
my $threads = $limit;
my @numbers = map { int(rand(100)) } 1..100;

sub REAPER {
    local $!;

    while( (my $pid = waitpid(-1, WNOHANG) ) > 0 && WIFEXITED($?) ) {
        $threads++;
    }

    $SIG{CHLD} = \&REAPER;
}

$SIG{CHLD} = \&REAPER;

for ( @numbers ) {
    while( $threads == 0 or $threads > $limit ) { usleep(1) }

    my $pid = fork();

    die $! unless defined $pid;

    if( $pid ) {
        # parent
        $threads--;
    } else {
        # child
        my $n = compute_square($_);
        printf "Process %6d: %3d => %d\n", $$, $_, $n;
        exit 0;
    }
}

sub compute_square {
    my $num = shift;

    return $num*$num;
}
Polar Bear
  • 6,762
  • 1
  • 5
  • 12