Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Shared hash within shared hash of hash???

by ISAI student (Scribe)
on Jan 02, 2013 at 11:18 UTC ( #1011249=perlquestion: print w/replies, xml ) Need Help??
ISAI student has asked for the wisdom of the Perl Monks concerning the following question:

Hello all. Is there any known pragma, in which one would decide to have the following code snippet:
use threads; use threads::shared ; my %a : shared = () ; $a{'foo'} = &share({}) ;
I mean, $a{'foo'} is already shared, right? What's the point in having it's elements shared too? The code that I am maintaining, has not a single lock command...

Replies are listed 'Best First'.
Re: Shared hash within shared hash of hash???
by zwon (Abbot) on Jan 02, 2013 at 11:43 UTC

    threads::shared keeps all shared variables in a separate interpreter. If you declared hash like:

    my %hash : shared = ();
    then hash and all its values will be stored in this dedicated interpreter. In case of:
    $hash{foo} = {};
    you creating anonymous hash in the current interpreter and saving reference to it in the shared interpreter which is not allowed, that's why you should create a shared copy:
    $hash{foo} = shared_clone({});
    Another possibility:
    my %tmp : shared = (); $hash{foo} = \%tmp;
      I seem to be getting better understanding...

      Two questions:

      1. Do i need to use  lock $hash{foo} ;
      or lock ( \%hash ) ; if foo is used as shared_clone ?

      2. Can I just use
      %{$hash{foo}} = () ;
      And just lock %hash, if needed?
        Do i need to use lock $hash{foo} ; or lock ( \%hash ) ; if foo is used as shared_clone ?
        You only need locking to ensure the consistency of your own data when shared between threads. Perl already does its own internal locking on shared structures to ensure internal consistency. So for example
        my %h : shared; $h{foo} = share ({}); ... $h{foo}{bar} = 1; # in thread 1 $h{foo}{bar} = 2; # in thread 2
        Here, there is no locking, so $h{foo}{bar} may end up as 1 or 2; but it won't end up as something else; nor will the {foo} or the {bar} slots of the respective hashes get corrupted.


        1. Do i need to use lock $hash{foo} ; or lock ( \%hash ) ; if foo is used as shared_clone ?

        It depends upon what you intend to modify.

        When you have nested hashes so:

        %hash :shared = &share( {} );
        1. To add a new key/value pair; or delete a key/value pair; or modify the value associated with an existing key in %hash you need:
          lock %hash; $hash{ existingkey } = newvalue; # or $hash{ newkey } = newvalue; #or delete $hash{ existingkey };
        2. To modify the nested anonymous hash associated with the key 'foo', you need:
          lock %{ $hash{ foo } }; $hash{foo}{somekey} = somevalue; # or delete $hash{ foo }{ somekey };

          Ie. lock %{ $h{1} } says lock the hash referenced by the value at $h{1}.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I'm not sure about the first one, as for the second -- why don't you try it?
Re: Shared hash within shared hash of hash???
by muba (Priest) on Jan 02, 2013 at 12:00 UTC

    I suspect that it has something to do with {} being a reference to another, newly created value. Let's break things down.

    my %a : shared = (); $a{foo} = {}; $a{bar} = 42;

    What I suspect to be happening here, is the following.

    The first line conveniently reads from left to right: my %a declares the hash in the current lexical scope in the current thread. : shared shares the hash with all other threads. = (); assigns the empty list to this hash.

    The next line has most of its action on the far right side. {}; creates an anonymous hash in the current thread. Due to being anonymous, it's not bound by any scope — it will simply live for as long as something references to it. So {} is kind enough to create and return that reference. That's right: a reference and the value it refers to, are in fact not the same entity. $a{foo} = then stores that reference under the key "foo" in the hash %a.

    If you want, you can see that {} creates a new value:

    print {}, "\n"; print {}, "\n";

    And the last line simply stores the number 42 in $a{bar}. There is no referencing here, and no creation of a new value. 42 will be 42, so there's no need to share it here.

    So my best guess, the reason you need to &share( {} ) is not because $a{foo} isn't shared, but because the anonymous hash that {} created, isn't shared.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1011249]
Approved by muba
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (10)
As of 2017-09-20 13:10 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (236 votes). Check out past polls.