How to access perl objects in threads

I hope one of you can help me with my problem. I tried to access the global shared array of objects during streaming computation and always got the error "use uninitialized value", although I can print my hashes.

Also, I cannot change my objects due to working with seqio objects from bioperl.

The following example shows my problem.

Thanks in advance.

object class:

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

Testing Class:

 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
source share
1 answer

section "Errors and limitations" in threads :: general documentation warns

When share used for arrays, hashes, arrays, or hash links, 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'})); 

Thus, write down such variables after , declaring them as general. (Scalar and scalar links are not affected by this issue.)

You lose data in newly created objects and set later warnings without initialization with

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

Note the other warning in the documentation on topics :: shared.

It is often unreasonable to share an object if the class itself has not been written to support sharing. For example, an object destructor may be called several times, once for each thread visibility thread. Another danger is that the contents of the hash-based objects will be lost due to the aforementioned restriction. See examples/class.pl (in the CPAN distribution of this module) for how to create a class that supports object sharing.

The code in obj.pm becomes

 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; 

Changes

  • Use streams and streams :: general modules.
  • Remove unused exporter spells.
  • In the constructor, create an empty shared hash, and then initialize and bless.
  • Add lock calls to accessors.

If you forget to delete the call to share in the loop, you will still receive all warnings. Change the loop to

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

to get the following conclusion.

  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 
+2
source

Source: https://habr.com/ru/post/1446401/


All Articles