如何在Perl中的调用之间存储每线程状态?

时间:2010-02-23 09:50:13

标签: perl multithreading thread-safety

现在根据我在Perl ithreads下的理解,除非明确共享,否则所有数据都是私有的。

我想编写一个函数来存储调用之间的每个线程状态。我假设默认情况下所有数据都是线程私有的副作用允许我使用这样的闭包:

#!/usr/bin/perl -w

use strict;
use threads;

{ # closure to create local static variable
    my $per_thread_state = 0;

    sub foo {
        my $inc = shift;
        $per_thread_state += $inc;

        return $per_thread_state;
    }
}

my $inc = 0;

threads->create(
    sub { 
        my $inc = shift;
        my $i = $inc; 
        while (--$i) { 
            threads->yield(); 
            print threads->tid().":".foo($inc)."\n";
        }
    }, $inc
) while (++$inc < $ARGV[0]);

$_->join() foreach threads->list();

当我运行它时,它看起来像我期望的那样工作,但我只是想确定,因为我找不到任何明确讨论这样做的文档。

有人能指出我正式看的东西吗?

修改

另一件似乎很奇怪的事情是,线程似乎总是按创建顺序运行,并且由于某种原因不会交错。例如,如果我跑:

./tsd.pl 100

所有东西都按顺序完美打印出来。如果重要的话,我会使用Ubuntu 9.04。

2 个答案:

答案 0 :(得分:2)

如果您运行的是Perl 5.9.4+,这似乎是使用state关键字的理想选择。如果启用了state,则只有foo()子例程才能修改$per_thread_state的值。

以下是:

use feature 'state';

sub foo {
    state $per_thread_state;
    my $inc = shift;
    $per_thread_state += $inc;
    return $per_thread_state;
}

请记住启用state(来自perlsub):

  

从perl 5.9.4开始,您可以使用state关键字来声明变量来代替my。但是,要使其正常工作,您必须事先启用该功能,方法是使用功能部件编目指示,或者在单行上使用-E。

perlsub还有Persistent Private Variable with Closures部分。你所做的似乎很好。

答案 1 :(得分:1)

创建每个线程状态的方法是正确的。

将Perl的线程视为处理IPC和分叉进程的更方便的方法通常会有所帮助。每次调用threads->create(...)都会克隆当前解释器及其中的所有内容,因此每个线程都会获得自己的foo()$per_thread_state的独立副本。当你加入一个线程时,你可以传回一个值,但是线程解释器状态中的所有其他东西都将被销毁。

您的线程在创建顺序中运行主要是由于Perl和操作系统中的实现细节(主要是因为它们的单独执行时间低于操作系统的最短执行时间片)。要交错线程,您可以使用sleep而不是屈服(或让线程做一些真正的工作)。