4

あなたの誰かが私の問題を解決してくれることを願っています。スレッド化された計算中にオブジェクトのグローバル共有配列にアクセスしようとすると、ハッシュを出力できますが、常に「初期化されていない値の使用」というエラーが発生します。

さらに、bioperl の seqio オブジェクトを使用しているため、オブジェクトを変更できません。

次の例は、私の問題を示しています。

前もって感謝します。

オブジェクトクラス:

package obj;

use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);

sub new(){
    my $class=shift;
    my $this = {};
    $this->{"data"} = ();   
    bless($this,$class);
    return($this);
}

sub getData(){
    my $this=shift;
    return $this->{"data"};
}

sub setData($){
    my $this=shift; 
    $this->{"data"}=shift;
}

テストクラス:

use strict;
use warnings;
use threads;
use threads::shared;
use obj;

my @objs : shared;
foreach (0..2){
    my $o = obj->new();
    $o->setData($_);
    push @objs, share($o);  
}

my @threads=();
$#threads=3;

my $started;
for (my $i=0; $i<10; $i+=$started){
    $started=0;
    foreach (0..$#threads){
        if (not defined $threads[$_]){
            $threads[$_]=threads->new(\&run,(\@objs));
            $started++; 
        } elsif($threads[$_]->is_joinable()){
            $threads[$_]->join();
            $threads[$_]=threads->new(\&run,(\@objs));
            $started++;
        }           
    }   
}
my $running=1;
while ($running>0) {
    foreach (@threads) {    
        if (defined $_){
            $_->join if ($_->is_joinable());    
        }               
    }
    $running = scalar(threads->list(threads::running));       
}   

sub run($){
    my $objs=shift;

    print $_." " foreach (@{$objs});
#   print $_->getData()." " foreach (@{$objs}); try to access data

    print "\n";     
}
4

1 に答える 1

2

スレッド::共有ドキュメントのバグと制限のセクションは警告します

shareが配列、ハッシュ、配列参照、またはハッシュ参照で使用される場合、それらに含まれるデータはすべて失われます。

[...]

# Create a 'foo' object
my $foo = { 'data' => 99 };
bless($foo, 'foo');

# Share the object
share($foo);        # Contents are now wiped out
print("ERROR: \$foo is empty\n")
    if (! exists($foo->{'data'}));

したがって、共有として宣言した後、そのような変数を設定します。(スカラーおよびスカラー参照はこの問題の影響を受けません。)

新しく作成されたオブジェクトのデータが失われ、後で初期化されていない変数の警告が設定されます

for (0..2) {
    my $o = obj->new();
    $o->setData($_);
    push @objs, share($o);  # wipes out $o
}

スレッド::共有ドキュメントの別の警告に注意してください。

クラス自体が共有をサポートするように作成されていない限り、オブジェクトを共有することは賢明ではないことがよくあります。たとえば、オブジェクトのデストラクタは、スレッドのスコープ出口ごとに1回ずつ、複数回呼び出される場合があります。もう1つの危険は、上記の制限により、ハッシュベースのオブジェクトのコンテンツが失われることです。examples/class.plオブジェクト共有をサポートするクラスを作成する方法については、(このモジュールのCPANディストリビューションで)を参照してください。

のコードobj.pm

package obj;

use strict;
use threads;
use threads::shared;
use warnings;

sub new {
    my $class=shift;
    share(my %this);
    $this{"data"} = ();
    bless(\%this,$class);
    return(\%this);
}

sub getData {
    my $this=shift;
    lock($this);
    return $this->{"data"};
}

sub setData {
    my $this=shift;
    lock($this);
    $this->{"data"}=shift;
}

1;

変更点は

  • スレッドとthreads::sharedモジュールを使用します。
  • 未使用のエクスポーターの呪文を削除します。
  • コンストラクターで、空の共有ハッシュを作成してから、初期化して祝福します。
  • lockアクセサにへの呼び出しを追加します。

ループ内のへの呼び出しを削除するのを忘れたshare場合でも、すべての警告が表示されます。ループをに変更します

foreach (0..2){
    my $o = obj->new();
    $o->setData($_);
    push @objs, $o;  # already shared!
}

次の出力を取得します。

0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
0 1 2
于 2012-12-01T15:47:25.867 に答える