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