共享线程变量而不使其全局化(Perl)

时间:2015-10-08 15:57:01

标签: multithreading perl scope lexical-scope

我正在尝试编写一个使用线程并共享变量的简单脚本,但我不希望将此变量设置为整个脚本的全局变量。以下是一个简化的例子。

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";
    }
}

输出:

  

用线程1做点什么!   有趣的是1

     

用线程2做点什么!   有些人是2

     

用线程3做点什么!   有趣的是3

     

用线程4做点什么!   有趣的是4

     

用线程5做点什么!   有些事情是5

     

VAL IS:SOMETHING为5

如何在不使整个脚本可以访问$val的情况下获得此效果?换句话说,我怎么能这样做,所以尝试打印VAL IS: $val会失败,但变量仍然会被线程成功共享?

我不能这样定义:

# Create threads
for my $i (1 .. 5) {
    my $val:shared;
    threads->create(\&do_something, $i);
}

或者我会得到:

  

全局符号“$ val”需要显式包

对词汇范围共享变量的正确方法是什么?

2 个答案:

答案 0 :(得分:4)

将引用作为参数传递给它。

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); };
   }
}

或范围它只有工人潜艇才能看到它。

{
   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); };
}

答案 1 :(得分:4)

您可以限制共享变量的范围(确保perl在创建线程之前看到共享变量),

# ..
{
  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);
}

# ...