http://www.perlmonks.org?node_id=526204

Elijah has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to share a hash table across numerous threads. I am able to share the hash by a simple:

my %hash : shared;

But then I try to assign a value to it by:

{lock(%hash); $hash{$arg1}->{$arg2}->{$arg3}->{$arg4} = $arg5;}
The error I get is: Invalid value for shared scalar at

Is what I am trying to accomplish possible?

Replies are listed 'Best First'.
Re: Sharing multitiered hash amongst multiple threads?
by BrowserUk (Pope) on Jan 28, 2006 at 21:51 UTC

    You can only assign references to shared arrays and hashes into shared hashes. You can either declare them shared and assign a reference:

    my %hash : shared; my @array : shared; my %hash2 : shared; $hash{ array } = \@array; $hash{ hash } = \%hash;

    Which is simple but often inconvenient. Or you can use threads::shared::share to them before assignment.

    There are two caveats with the second approach.

    1. If you share a pre-existing hash or array that already contains data, that data is discarded.
    2. The share() sub uses a prototype which rejects attempts to share anonymous structures.

    You can make life a little easier by bypassing the prototypes using $sharedHash{ key } = &share( {} ) and $sharedHash{ key } = &share( [] ), but don't be tempted to do $sharedHash{ key } = &share( [ 'some', 'stuff', 'here' ] );because the contents will be discarded.

    An example

    #! perl -slw use strict; use threads; use threads::shared; use Data::Rmap; sub thread { my( $hashref ) = @_; rmap{ print "$_"; } $hashref; } my %hash : shared; $hash{ leaf } = 'fred'; $hash{ L1 } = &share( {} ); $hash{ L1 }{ leaf } = 'wilma'; $hash{ L1 }{ L2 } = &share( {} ); $hash{ L1 }{ L2 }{ leaf } = 'bam bam'; $hash{ L1 }{ L2 }{ L3 } = &share( {} ); $hash{ L1 }{ L2 }{ L3 }{ leaf } = 'flintstone'; threads->create( \&thread, \%hash )->join; __END__ P:\test>junk2 fred wilma bam bam flintstone

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Sharing multitiered hash amongst multiple threads?
by zentara (Archbishop) on Jan 28, 2006 at 21:04 UTC
    When you declare a hash as shared that way, it only works for the first level keys. You need to specifically declare each level as shared. Like this. I always do it manually, but you could setup some sort of loop to declare your deep levels. Remember, you need to declare them as shared before you assign a value.
    foreach my $dthread(1..$numworkers){ share ($shash{$dthread}{'go'}); share ($shash{$dthread}{'progress'}); share ($shash{$dthread}{'timekey'}); #actual instance of the thread share ($shash{$dthread}{'frame_open'}); #open or close the frame share ($shash{$dthread}{'handle'}); share ($shash{$dthread}{'data'}); share ($shash{$dthread}{'pid'}); share ($shash{$dthread}{'die'}); $shash{$dthread}{'go'} = 0; $shash{$dthread}{'progress'} = 0; $shash{$dthread}{'timekey'} = 0; $shash{$dthread}{'frame_open'} = 0; $shash{$dthread}{'handle'} = 0; $shash{$dthread}{'data'} = $data; $shash{$dthread}{'pid'} = -1; $shash{$dthread}{'die'} = 0; $hash{$dthread}{'thread'} = threads->new(\&work,$dthread); }

    I'm not really a human, but I play one on earth. flash japh