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


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

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.

Replies are listed 'Best First'.
Re^2: PERL issues a "lock can only be used on shared values" when locking a shared hash
by Anonymous Monk on Apr 26, 2013 at 06:43 UTC
    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.
Re^2: PERL issues a "lock can only be used on shared values" when locking a shared hash
by sundialsvc4 (Abbot) on Apr 26, 2013 at 01:32 UTC

    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;