如何在线程中访问Perl对象 [英] how to access perl objects in threads

查看:55
本文介绍了如何在线程中访问Perl对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I hope someone of you is able to help me with my problem. I tried to access a global shared array of objects during a threaded computation and always get the error "use of uninitialized value" although I can print their hashes.

此外,由于使用bioperl中的seqio对象,因此无法更改对象.

In addition I can not change my objects, due to working with seqio objects from bioperl.

以下示例显示了我的问题.

The following example shows my problem.

谢谢.

对象类:

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";     
}

推荐答案

错误::共享文档的警告和限制部分

在数组,散列,数组引用或哈希引用上使用share时,它们包含的任何数据都会丢失.

When share is used on arrays, hashes, array refs or hash refs, any data they contain will be lost.

[...]

# 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'}));

因此,请在之后填充此类变量,以将其声明为共享变量. (标量和标量引用不受此问题的影响.)

Therefore, populate such variables after declaring them as shared. (Scalar and scalar refs are not affected by this problem.)

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

You lose the data in newly-created objects and set up later uninitialized-variable warnings with

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

在thread :: shared文档中注意另一个警告.

Note another warning in the threads::shared documentation.

除非编写类本身来支持共享,否则共享对象通常是不明智的.例如,一个对象的析构函数可能被调用多次,每个线程的作用域出口一次.另一个危险是由于上述限制,基于散列的对象的内容将丢失.请参阅 examples/class.pl (在CPAN发行版中有关如何创建支持对象共享的类的说明.

It is often not wise to share an object unless the class itself has been written to support sharing. For example, an object’s destructor may get called multiple times, once for each thread’s scope exit. Another danger is that the contents of hash-based objects will be lost due to the above mentioned limitation. See examples/class.pl (in the CPAN distribution of this module) for how to create a class that supports object sharing.

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;

更改是

  • 使用线程和thread ::共享模块.
  • 删除未使用的Exporter标记.
  • 在构造函数中,创建一个空的共享哈希,然后初始化并祝福.
  • 在访问器中向lock添加呼叫.
  • Use the threads and threads::shared modules.
  • Remove the unused Exporter incantations.
  • In the constructor, create an empty shared hash and then initialize and bless.
  • Add calls to lock in the accessors.

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

If you forget to remove the call to share in the loop, you still get all the warnings. Change the loop to

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

这篇关于如何在线程中访问Perl对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆