in reply to Re: threads::shared - when to lock a hash ?
in thread threads::shared - when to lock a hash ?

You always have to lock shared variable when you accessing it
Wrong. Perl internally locks the variable before reading from or writing to it, so you don't need to lock it to avoid a corrupted value.

As to the OP's questions: R1 is safe, while R2 behaves like R3: i.e. it iterates over the hash pushing individual values onto @x. In R3, if another thread is adding or deleting elements, or also iterating, then it will affect the result in the same way as if a single thread was doing it, e.g.

while (($k, $v) = each(%h)) { # stuff here which adds or deletes elements, # or uses each/keys/values }
W1,2,3 are all safe.

Of course in all the above, "safe" means "not corrupting perl's internal state"; perl's internal locking causes all the reads and writes to be serialised. You may of course still need to do locking at a higher level to ensure the safety of your own code's logic

Dave.

Replies are listed 'Best First'.
Re^3: threads::shared - when to lock a hash ?
by zwon (Abbot) on Oct 16, 2011 at 14:26 UTC
    Perl internally locks the variable before reading from or writing to it

    Thanks, I should have thought that perl somehow protects its internal state. I couldn't find anything in threads::shared manual, so I looked into source and what I understand is that perl locks not just variable but the whole shared space, is it correct?

      perl locks not just variable but the whole shared space, is it correct?
      Yes.

      All shared variables are kept in a separate interpreter, with stub copies of the variable in each thread, and a tieing mechanism used to access the vars. So when you do something like $shared_var = 1, your thread notes that $shared_var is tied, an calls the STORE method (which happens to be implemented in XS for efficiency). This method sets a global lock and copies the new value to the 'real' variable.

      Dave.

Re^3: threads::shared - when to lock a hash ?
by ikegami (Patriarch) on Oct 17, 2011 at 03:43 UTC

    so you don't need to lock it to avoid a corrupted value.

    It's possible that the ops return junk if all the lock does is avoid corruption. I'm not sure this answers anything.

    For starters, does a hash have one iterator per thread or just one iterator? each and possibly keys aren't safe if it's the latter.

      The ops never return junk; they will return values consistent with whatever thread did the most recent update. For example, this will never die:
      use threads; use threads::shared; my $x : shared; for (0..9) { threads->new(sub { while (1) { $x = $_[0]; die unless $x =~ /^\d$/; } }, $_ ); } sleep;
      There is one iterator per shared object, which is why I mentioned earlier that if other threads do each/keys/value too, it will affect the result

      Dave.

        So each isn't thread safe. That brings us to keys. Is keys uninterruptible, or just the parts that would cause corruption?

        Update: No, keys isn't thread safe either.

        use strict; use warnings; use threads; use threads::shared; use feature qw( say ); use constant NUM_THREADS => 10; my %h :shared = map { $_ => 1 } 'a'..'z'; my $size = () = keys(%h); my $done :shared; my @threads; for (1..NUM_THREADS) { push @threads, async { while (!$done) { my $test_size = () = keys(%h); if ($test_size != $size) { warn("$test_size != $size\n"); return; } } }; } sleep(10); $done = 1; $_->join() for @threads;
        11 != 26 42 != 26 15 != 26 38 != 26 13 != 26 41 != 26 15 != 26 41 != 26 13 != 26 45 != 26