代码之家  ›  专栏  ›  技术社区  ›  pilcrow

线程化Perl中的未锁定共享哈希操作安全性

  •  3
  • pilcrow  · 技术社区  · 14 年前

    问题

    多个线程在 shared 无散列 lock() 哈希?

    你能证明或引用强有力的权威吗?

    背景

    我的信念是,最坏情况下,解锁散列操作可能导致segfaults。

    但是,我最近看到了以这种方式协调工作线程活动的代码,作者认为这是安全的。相关代码只执行简单的提取和存储:

    • 共享哈希是一个普通的共享哈希(不是用户定义的tie()d构造)
    • 这些值是简单的标量,不是引用,它们本身也不是共享的。
    • 每个键/值对由一个且只有一个线程唯一地存储和修改。
    • 所有键/值对都可以由任何线程获取
    • 没有线程迭代共享哈希(没有 each() 没有 keys() 也不 values() 循环)

    代码摘录

    my %status : shared;
    
    for my $id (1 .. $n) {
      threads->create(\&thread_routine);
    }
    
    sub thread_routine {
      my $me = threads->tid();
    
      $status{ $me } = 'Getting ready';
      ... do something ...
      $status{ $me } = 'Thinking';
      ... do something else ...
    
      $status{ $me } = 'Looking around';
      for my $tid (threads->list) {
        next if $tid == $me;
        if ($status{ $tid } eq "Thinking") { ... react ... }
        ...
      }
    
      $status{ $me } = 'All done';
    }
    
    3 回复  |  直到 13 年前
        1
  •  1
  •   Daniel C. Sobral    13 年前

    这是权威的答案。从 perlthrtut ,在“共享和非共享数据”结尾处,

    注意,共享变量保证 如果两个或多个线程尝试 同时修改它, 变量的内部状态将 没有损坏。然而,那里 除此之外没有任何保证,如 在下一节中解释。

    所以, 是的,在散列中不加锁地存储和获取简单的单个值是安全的。

        2
  •  2
  •   cjm    14 年前

    我的理解是,为了防止散列内部结构的损坏,任何必要的锁都是自动处理的。这个 lock 函数的作用是允许线程进行协调,以保持哈希的更高级别一致性。因为在这种情况下,每个键只由一个线程修改,所以不需要显式锁定。

    我不能引用权威,除非我在 threads::shared 说明在修改变量之前需要小心锁定变量的文档。如果这样做可能导致Perl崩溃,您会认为值得一提。

        3
  •  1
  •   hlynur    14 年前

    唔,这样行吗?

    threads module docs 只需提到不要在结束块中使用线程,并且除了这个之外,在任何地方都不要提到互斥体。如果互斥锁是必需的,那么它们肯定会包含在线程模块中——但它们不是,是吗?

    my %hash : shared;
    
    map {
            async { map { $hash{$_}++; } (1 .. 30); }
    } (1 .. 300);
    
    map {$_->join} (threads->list);
    
    print Dumper \%hash;
    

    每次运行时,每个键中都有一个get值300。到目前为止,我找不到更好的方法来证明它是安全的。