P0w3rK!d has asked for the wisdom of the Perl Monks concerning the following question:


Why is it that I can create a regular hash and fill it as follows?

our $HSH();
our %HSH();

$HSH{123}{456} = "foo.xml"; # works fine

..but when I create a shared hash and populate it the same way it fails?

our $HSH2 : shared = ();
our %HSH2 : shared = ();

$HSH2{123}{456} = "foo.xml"; # fails

The error is as follows:

Invalid value for shared scalar at C:\foo.pl line 248.


Fixed typos at author's req - dvergin 2003-05-20

  • Comment on Threading: Invalid value for shared scalar

Replies are listed 'Best First'.
Re: Threading: Invalid value for shared scalar
by BrowserUk (Pope) on May 20, 2003 at 19:58 UTC

    The problem is that you cannot (yet) share a nested references using threads::shared.

    What you are sharing is not a hash but a scalar $HSH2. You are then

    1. auto-vivifying an anonymous hash,
    2. assigning a reference to that hash to $HSH2
    3. auto-vivifying another anonymous hash
    4. assigning the ref of that to an element of the first anon. hash.
    5. Assigning your string to an element in the second anon. hash.

    Too many words, but your 2 lines of code

    our $HSH2 : shared = (); $HSH2{123}{456} = "foo.xml"; # fails

    Is equivalent to

    # Why initialise a scalar to an empty list? our $HSH2 :shared = (); # Assign a ref to an anonymous hash $HSH2 = {}; # Assign a ref to another anon. hash to a new element of the first. $HSH2->{123} = {}; # Assign a string to an element of the second. $HSH2->{123}->{456} = 'foo.xml';

    threads::shared only allows you to share a single level of shared structure, and this is three levels deep, hence the "Invalid value" .

    Not a very good error message. It ought really read something like:

    Assigning a reference to an element of a shared hash or array is not allowed.

    I'm also not certain that sharing an our'd variable is a "good thing", as it is a lexified global. May be fine, but I've never tried it and it gives me an uneasy feeling.

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
      I put in a request to fix the code. It was not filled at the time of your review.

      I'm going to have to create a separate shared hash of keys to mainpulate separate unshared hash (n) times. What a pain!!! :(


        You can share nested hash, as long as the internal hashes are also marked as shared. Let's say your non-shared code to populate the hash looked like this:
        #non shared hash version my %abc; my @parents = qw( a b c ); my @children = qw( 1 2 3 4 ); for my $parent ( @parents ) { for my $child ( @children ) { $abc{ $parent }{ $child } = 1; } }
        Changing the implicit hash creation to explicit hash creation will fix the problem. the perl thread model is predicated on non-shared data by default. This forces us to deliberately share all the structures. (It is a pain).
        # shared hash version. my %abc : shared ; my @parents = qw( a b c ); my @children = qw( 1 2 3 4 ); for my $parent ( @parents ) { unless (exists $abc{$parent}) { my %p : shared; $abc{ $parent } = \%p; } for my $child ( @children ) { unless ( exists $abc{$parent}{$child} ) { my %c : shared; $abc{$parent}{$child}=\%c; } $abc{ $parent }{ $child } = 1; } }
        The lexical scopes for %p and %c will go away, but the references will remain in the hash, preventing garbage collection.
Re: Threading: Invalid value for shared scalar
by djantzen (Priest) on May 21, 2003 at 01:36 UTC
      my %hm_n2g:shared = (); my $row = &share([]); $hm_n2g{"aa"}=$row; $row->[0]=1; $row->1=2; my @arr = @{$hm_n2g{"aa"}}; print @arr[0]." ".@arr1."\n";