Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

PERL issues a "lock can only be used on shared values" when locking a shared hash

by ISAI student (Scribe)
on Apr 25, 2013 at 13:48 UTC ( #1030674=perlquestion: print w/ replies, xml ) Need Help??
ISAI student has asked for the wisdom of the Perl Monks concerning the following question:

Hello all. I am trying to lock a hash that is wihtin another hash, when using another hash, within a sub & I am getting the error above. Code is:
use strict; use threads; use threads::shared; use warnings; sub lockit($) { my $uber_hashRef = shift ; print "Yey\n" if is_shared( $$uber_hashRef{'%y'} ) ; lock ($$uber_hashRef{'%y'}) ; } sub genSharedLower($) { my $hashRef = shift ; $$hashRef{'%y'} = &share({}) ; } my %all_shary_for_subs : shared ; genSharedLower(\%all_shary_for_subs); print "Yey\n" if is_shared( $all_shary_for_subs{'%y'}); lockit( \%all_shary_for_subs) ;

Output is:

Yey
Yey
lock can only be used on shared values at shared_issue.pl line 8.

How is the value that was acknoledged as shared in line 7 be unshared in line 8?
Thanks!

Comment on PERL issues a "lock can only be used on shared values" when locking a shared hash
Download Code
Re: PERL issues a "lock can only be used on shared values" when locking a shared hash
by SuicideJunkie (Priest) on Apr 25, 2013 at 22:27 UTC

    Quoth the CPAN:

    share() allows you to share($hashref->{key}) and share($arrayref->[idx]) without giving any error message. But the $hashref->{key} or $arrayref->[idx] is not shared, causing the error "lock can only be used on shared values" to occur when you attempt to lock($hashref->{key}) or lock($arrayref->[idx]) in another thread.

    I can't say how effective this is, but the following tweak gets a local direct reference to the shared hash instead of following a dereference in the lock call, and doesn't complain.

    use strict; use threads; use threads::shared; use warnings; sub lockit($) { my $uber_hashRef = shift ; print "Yey\n" if is_shared( $$uber_hashRef{'%y'} ) ; my $subHash = $uber_hashRef->{'%y'}; lock ($subHash) ; print "Done!\n"; } sub genSharedLower($) { my $hashRef = shift ; $$hashRef{'%y'} = &share({}) ; } my %all_shary_for_subs : shared ; genSharedLower(\%all_shary_for_subs); print "Yey\n" if is_shared( $all_shary_for_subs{'%y'}); lockit( \%all_shary_for_subs) ;
    Gives:
    C:\Documents and Settings\nd250020\Desktop\dev>perl test.pl Yey Yey Done!
Re: PERL issues a "lock can only be used on shared values" when locking a shared hash
by sundialsvc4 (Abbot) on Apr 25, 2013 at 22:33 UTC

    Now, here is a pure-curiosity question ... since I try to avoid perlguts as much as possible.   What is the entity that lock actually locks?   Is it an item of data, or is it a symbol-table entry?   If you have two variables referring to the same piece of data, say, and lock one of them, what is actually going to be seen as locked or not?

Re: PERL issues a "lock can only be used on shared values" when locking a shared hash
by BrowserUk (Pope) on Apr 26, 2013 at 00:28 UTC

    Your code makes no sense.

    1. First the headline issue of the error:lock can only be used on shared values ...

      The problem here is that you are trying to lock the value of a key which is a reference to a shared hash; but the reference is not (and cannot be) shared, only the hash that it refers to is shared.

      Thus to lock the subhash, you need to dereference that hash reference. Eg.:

      lock %{ $uber_hashRef{'%y'} };
    2. But, the more important issue is that it makes no sense to wrapover lock in a user subroutine.

      Locks only persist for the duration of the lexical scope in which they are applied. Hence, by the time your lockit() subroutine returns, the lock will have been released; so the effect of calling it will be nothing.


    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.

      BrowserUK, I certainly would benefit from an explanation ... in this thread or in a separate one (referenced from here) ... as to what the “granularity” of the lock semantics in Perl actually are.   “What, exactly, is ‘the thing that you can lock?’”   Is it .. a data item? .. the hash-structure itself? .. a particular reference-point?   This subtle point is, to me, the essential question here, and I do not know the answer, but I am quite certain that you do.

      The objective of “locking a data-structure in Perl” is certainly not a simple one, given that the entire data management system is centered around the notion of “references.”   There is no hierarchy ... anything can refer to anything, and those references can come both from language-variables and from the various data items themselves.   The implementation has to have made certain decisions ... simplifications.   I’d very much like to hear you elucidate what they are.

      Seriously.

        The objective of “locking a data-structure in Perl” is certainly not a simple one,

        On the contrary, the objective locking shared variables is very simple.

        It is to prevent one thread from accessing the locked entity whilst the lock is held by another thread.

        given that the entire data management system is centered around the notion of “references.”

        Scalars, arrays and hashes are not references.

        There is no hierarchy ... anything can refer to anything,

        I cannot make any sense of the first part of that statement, because it is immediately contradicted by the second part.

        Arrays and hashes contain scalars; and scalars can hold references; and those references can be to other arrays or hashes, hence they can be used to construct hierarchies. Just as in C, arrays of integers can be used to construct hierarchies if some of those integers happen to be pointers to other entities.

        I started to point out that no language has hierarchies by default; but then I couldn't justify that because your statement simply makes no sense.

        Your lack of understanding -- not just of threading, but Perl, and even programming, in general -- makes it all more frustrating and annoying that you once again have started to dole out "advice" on subjects you simply know nothing useful about.


        Now to try and answer the only question that makes any sense:

        what the “granularity” of the lock semantics in Perl actually are.

        When an entity is locked by one thread; and another thread attempts to take a lock on that same entity; it is blocked -- ie., the lock does not return -- until the first thread unlocks that entity by exiting the scope in which the lock was taken. And that is it.

        Now to clarify a few common misunderstandings.

        • It is perfectly possible to modify a shared entity, locked by one thread, from another thread, whilst it is locked.

          It is the act of taking the lock that prevents that thread from doing anything else (to that entity or anything else).

          Stated differently, the lock taken by the first thread does not prevent a second thread from doing anything; only the attempt by the second thread to obtain a lock on an already locked entity.

        • The elements of a shared aggregate -- a hash or array -- are not themselves shared.

          They are bog standard scalars.

          If however, you store a reference to another shared hash in a hash, you can then lock that other shared hash by applying lock to it via that reference -- by dereferencing it first.

        • It is also perfectly valid to store a reference to a shared entity within a non-shared aggregate.

          The semantics of doing so are a little confusing, but it has its uses.

        perhaps this will clarify things: Taking a lock on a shared entity effectively just sets a flag within its internals. And whilst that flag is set, any further attempt to take a lock on that entity blocks until the lock is cleared when the thread that took the lock exits the scope in which it was taken.

        But the lock is advisory. If you attempt to modify a locked entity without attempting to take a lock on it first, the modification will succeed. Eben if that means that the code running in the thread that took the lock is rendered incorrect.

        The internals of the shared entity will be fine -- an internal, non-user lock will prevent damage to the internals of the entity -- but those internal locks know nothing of the semantics of the user code and it may therefore be rendered incorrect. But it will not crash.


        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.

        .... Seriously.

        so you've read threads::shared? Cause it gives examples

        You cannot lock the individual elements of a container variable:
        my %hash :shared; $hash{'foo'} = 'bar'; #lock($hash{'foo'}); # Error lock(%hash); # Works
        lock follows references exactly one level:
        my %hash :shared; my $ref = \%hash; lock($ref); # This is equivalent to lock(%hash)

        lock %{ $uber_hashRef{'%y'} };

        is like my $ref = $uber_hashRef{'%y'}; lock $ref;

        is like my $ref = $uber_hashRef{'%y'}; lock %$ref;

      Hi. I think that that it does make sense, considering I took the original problem (well over hundereds lines of code) and downsized it to something easily shared. In the original code, there is, of course, a lot going around AFTER the lock was advised.
        I think that that it does make sense, considering I took the original problem ... and downsized it to something easily shared.

        The code as posted doesn't make sense. (I cannot see the bits you omitted.)

        It's also a bit weird to name a subroutine lockit(), if in addition to locking something, it goes on to process that something (for hundreds of lines).

        In general, you'll get better advice and solutions if you don't hide the real code.

        (I know that flies in the face of the common advice for sites like this, but with the non-determinacy of threading far more so than with non-threaded code, being able to see (and preferably run) the actual code, is pretty much a prerequisite to provide good help and advice.)


        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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1030674]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (7)
As of 2014-10-31 07:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (215 votes), past polls