I'm trying to write a simple script that uses threads and shares a variable, but I don't want to make this variable global to the whole script. Below is a simplified example.
use strict;
use warnings;
use threads;
use threads::shared;
my $val:shared;
# Create threads
for my $i (1 .. 5) {
    threads->create(\&do_something, $i);
}
# Wait for all threads to complete
map { $_->join(); } threads->list();
# $val is global to the script so this line will work!
print "VAL IS: $val\n";
sub do_something {
    my $i = shift;
    print "Doing something with thread $i!\n";
    {
        lock $val;
        $val = "SOMETHING IS $i";
        print "$val\n\n";
    }
}
Output:
Doing something with thread 1! SOMETHING IS 1
Doing something with thread 2! SOMETHING IS 2
Doing something with thread 3! SOMETHING IS 3
Doing something with thread 4! SOMETHING IS 4
Doing something with thread 5! SOMETHING IS 5
VAL IS: SOMETHING IS 5
How can I get this effect without making $val accessible to the whole script?  In other words, how can I make it so attempting to print VAL IS: $val will fail, but the variable will still be successfully shared by the threads?
I can't define it like this:
# Create threads
for my $i (1 .. 5) {
    my $val:shared;
    threads->create(\&do_something, $i);
}
Or I will get:
Global symbol "$val" requires explicit package
What is the right way to lexically scope a shared variable?
Pass a reference to it as an argument.
sub do_something {
   my ($id, $lock_ref) = @_;
   print("$id: Started\n");
   {
      lock $$lock_ref;
      print("$id: Exclusive\n");
      sleep(1);
   }
   print("$id: done.\n");
}
{
   my $lock :shared;
   for my $id (1..5) {
      async { do_something($id, \$lock); };
   }
}
Or scope it so only the worker subs can see it.
{
   my $lock :shared;
   sub do_something {
      my ($id) = @_;
      print("$id: Started\n");
      {
         lock $lock;
         print("$id: Exclusive\n");
         sleep(1);
      }
      print("$id: done.\n");
   }
}
for my $id (1..5) {
   async { do_something($id); };
}
                        You can limit the scope of shared variable (make sure that perl sees shared variable before thread creation),
# ..
{
  my $val:shared;
  sub do_something {
      my $i = shift;
      print "Doing something with thread $i!\n";
      {
          lock $val;
          $val = "SOMETHING IS $i";
          print "$val\n\n";
      }
  }
}
# Create threads
for my $i (1 .. 5) {
    threads->create(\&do_something, $i);
}
# ...
                        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