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

Hi Monks, I have a hash I want to pass back from a thread via shared memory. Having done that for many years and quite reliably so with every other data type, this has me a little bit surprised. Note I have left out shared memory access synchronisation calls for simplicity in this example (I coordinate access via semaphores normally). In the code below, I am simply getting a "Magic number checking on storable string failed at /System/Library/Perl/5.18/darwin-thread-multi-2level/Storable.pm line 417, at ./test.pl line 46" error and it won't even run. Can anybody see the problem?
#!/usr/bin/perl -w use strict; use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR S_IRWXU IPC_CREAT IPC_EXC +L); use IPC::SharedMem; use Storable qw(freeze thaw); my %somehash; $somehash{'one'}{'count'} = 1; $somehash{'one'}{'string'} = "This is a big ol' string"; use constant { STOP => 0, RUN => 1 }; my $shm_mastercontrol = IPC::SharedMem->new(IPC_PRIVATE, 8, S_IRWXU); my $shm_somehash = IPC::SharedMem->new(IPC_PRIVATE, 1024, S_IRWXU); $shm_mastercontrol->write(pack("S", RUN), 0, 2); # forks processes my $thread_PID = fork(); if (not defined $thread_PID) { die "Insufficient resources to fork Runner!\n"; } elsif ($thread_PID == 0) { &thread(); } sub thread() { #my $string; while () { # increment the somehash counter: $somehash{'one'}{'count'}++; print "thread sees: $somehash{'one'}{'count'}\n"; my $serialized = freeze \%somehash; $shm_somehash->write(pack("A*", $serialized), 0, 1024); last if ( unpack("S", $shm_mastercontrol->read(0, 2)) == STOP); select(undef, undef, undef, 1.0); } exit(0); } while () { my $unpacked = unpack("A*", $shm_somehash->read(0, 1024)); # put somehash back from shared memory: %somehash = %{thaw($unpacked)}; print "main sees: $somehash{'one'}{'count'}\n"; print "press some key, q to quit:\n"; chomp (my $key = <STDIN>); if ( $key eq 'q' ) { $shm_mastercontrol->write(pack("S", STOP), 0, 2); waitpid($thread_PID, 0); last; } }

Replies are listed 'Best First'.
Re: can't thaw a hash: Magic number error.
by BrowserUk (Patriarch) on Nov 03, 2015 at 11:04 UTC

    Why are you packing the serialised hash?:

    $shm_somehash->write(pack("A*", $serialized), 0, 1024);

    Given that with A*, the result is identical to the original string:

    $s = ''; $s .= chr( $_ ) for 0 .. 255;; $A = pack 'A*', $s;; print $A cmp $s;; 0

    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". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That is a good question... a leftover from the normal operation of packing ints for copying via shared memory. I was under the assumption that the pack function is the only way to get the data written as a byte sequence into the shared memory. Are you suggesting I can write that into the shared memory block as is? Trying to read it back from the shared memory block doesn't bode well: %somehash = %{thaw($shm_somehash->read(0, 1024))}; causes: Byte order is not compatible at /System/Library/Perl/5.18/darwin-thread-multi-2level/Storable.pm line 417, at ./test.pl line 47

        I suspect the problem is that, in either case, the length of the value returned from shared memory is a full 1024 bytes despite that the length of the original frozen hash is less that 100 bytes. It is probably those extra bytes -- that might be space or null padded; or just random garbage -- that are upsetting the thaw process.

        Without having tested it -- IPC::SysV doesn't work on my system -- what I think you should be doing is something like this:

        my $serialized = pack 'L/a', freeze \%somehash; $shm_somehash->write( $serialized, 0, 1024); ... my $unpacked = unpack "L/a", $shm_somehash->read( 0, 1024); my %hash = %{ thaw $unpacked };

        The idea being that the 'L/a' template packs the string with a prefix of the number of characters that are packed. Thus when you unpack it, despite that you read back 1024 bytes from the shared memory, only the same number of bytes as where in the original freeze'd string will be returned, devoid of any packing, and (hopefully) when you pass that to thaw, it should be exactly what it is expecting.


        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". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.