如何在线程中访问perl对象



我希望你们中有人能帮我解决这个问题。我试图在线程计算期间访问对象的全局共享数组,但总是会收到错误"使用未初始化的值",尽管我可以打印它们的哈希。

此外,由于使用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";     
}

线程的Bugs and Limitations部分::共享文档警告

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 emptyn")
if (! exists($foo->{'data'}));

因此,在声明这些变量为共享变量之后填充这些变量。(标量和标量参考不受此问题的影响。)

您会丢失新创建的对象中的数据,并在以后使用设置未初始化的变量警告

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

请注意线程中的另一个警告::共享文档。

共享对象通常是不明智的,除非类本身已被编写为支持共享。例如,对象的析构函数可能被调用多次,每次调用一次用于每个线程的作用域出口。另一个危险是,由于上述限制,基于哈希的对象的内容将丢失。请参阅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;

这些变化是

  • 使用线程和线程::共享模块
  • 删除未使用的Exporter咒语
  • 在构造函数中,创建一个空的共享哈希,然后初始化并祝福
  • 在访问者中添加对lock的调用

如果您忘记在循环中删除对share的调用,您仍然会收到所有警告。将循环更改为

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

以获得以下输出。

0 1 20 1 20 1 20 1 20 1 20 1 20 1 20 1 20 1 20 1 20 1 20 1 2

最新更新