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

I humbly seek wisdom. The book of perlref says "When a scalar is holding a reference, it always behaves as a simple scalar" (Description, paragraph 5, verse 3)

Why then can I not put a hashref on a queue in Thread::Queue?

Example:

my $DataQueue = Thread::Queue->new; my $href = {'A'=>'1', 'B'=>'2', 'C'=>'3' }; $DataQueue->enqueue($href);

which produces:

Invalid value for shared scalar at C:/Perl/lib/Thread/Queue.pm line 90 +.

I understand that Thread::Queue only supports scalars, but I thought a reference was a scalar.

Also, is there a way to trick PERL into treating $href as a scalar?

Replies are listed 'Best First'.
Re: scalars, references and queues
by liverpole (Monsignor) on Aug 03, 2007 at 14:29 UTC
    It's because the other threads don't know anything about the data space where the hash was created, so having a pointer (ie. reference) to the hash is meaningless.

    Think of it this way -- you're a Perl program (or even just a separate thread), and I give you the data:

    HASH(0x804c8d4)

    Can you tell what the original values of the hash are?  Certainly not -- that information has been lost.  All you now know is the address of the hash, but it's in my memory space, so it doesn't allow for the reconstruction of the data.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: scalars, references and queues
by ikegami (Patriarch) on Aug 03, 2007 at 14:30 UTC

    Sharing a reference to something that isn't shared is an error. As threads::share says,

    my $var :shared; $var = 1; # ok $var = []; # error $var = &share([]); # ok

    Maybe Thread::Queue should handle references better. Fortunately, it's easy to fix. Just share the referenced hash.

    my %hash :shared = ( ... ); $DataQueue->enqueue(\%hash);

    or

    # Fixed as per BrowserUK's reply. # Initialization must be done after share. my $href = share({}); %$href = ( ... ); $DataQueue->enqueue($href);

    or

    use Storable qw( freeze thaw ); my %hash = ( ... ); $DataQueue->enqueue(freeze(\%hash));

    Untested.

    Update: Added Storeable snippet. Rephrased some text.

      A note of caution. Using

      my $href = { ... }; $DataQueue->enqueue(share($href));

      Is dangerous, because whatever you put inside the anonymous hash, represented in your exampe by ..., will be silently discarded when you do share( $href ).

      You must share the reference first, and then populate it.


      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: scalars, references and queues
by Anonymous Monk on Aug 03, 2007 at 15:11 UTC

    Wonderful! you monks move so fast!

    I think I still have some questions, but must digress into context to motivate them

    My concept is to pipeline some data through several threads, passing data between threads via queues. I wish to put a reference to an anonymous hash on the first queue, then have the first thread take it off, read it's values, create one or more anonymous hashes and pass them on to the next queue.

    The original hash does not get changed by the thread, though it's keys and values will get copied to all the new hashes created by the thread (for this iteration of the while

    my $inqueueref = shift; my $outqueueref = shift; my %inhash; while (%inhash = $inqueueref->dequeue) { #create one or more new anonymous hashes and $outqueue->enqueue(\%ou +thash) }

    ).

    Note that the relationship between the number of %inhashes and %outhashes is one:many.

    Note that any given hash is only shared by two threads; the one creating it and the next one (reading it).

    Now here's the follow-on question: How does the above solution using threads::shared change when the hashes are all anonymous hashes?

    or do I need some monster "global array of hashes" package whith lots of thread-safe methods encapsulating it and protecting it from direct access by all these threads (possibly putting the array index on the queues in this implementation)? I sure hope not.

      Thanks to all. Some hard meditation and I've gotten to a simplified skeleton that I think solves everything. If you see anything worth warning me about, I would love to hear it.

      I'm putting the proof of concept code in <readmore> tags. The work file was called "sharedanonymoushashrefs.pl", so that explains some of the naming conventions (sahr_).