Unlocked, shared hash operation safety in threaded perl
Question
Is it safe for multiple threads to fetch and store simple, individual values in a shared hash without lock()
ing the hash?
Can you prove it or cite strong authority?
Background
My belief was that at worst unlocked hash manipulations could lead to segfaults.
However, I've very recently seen code that coordinates worker threads' activity in such a manner, which the author believes to be safe. The code in question performs only simple fetches and stores:
- The shared hash is a plain, shared hash (not a user-defined, tie()d construct)
- The values are simple scalars, not references and not themselves shared
- Each key/value pair is uniquely stored and modified by one and only one thread
- All key/value pairs may be fetched by any thread
- No thread iterates through the shared hash (no
each()
, nokeys()
norvalues()
looping)
Code Excerpt
my %status : shared;
for my $id (1 .. $n) {
threads->create(\&thread_routine);
}
sub thread_routine {
my $me = threads->tid();
$status{ $me } = 'Getting ready';
... do something ...
$status{ $me } = 'Thinking';
... do something else ...
$status{ $me } = 'Looking around';
for my $tid (threads->list) {
next if $t开发者_开发技巧id == $me;
if ($status{ $tid } eq "Thinking") { ... react ... }
...
}
$status{ $me } = 'All done';
}
Here's an authority answer. From the perlthrtut, at the end of the "Shared and Unshared Data",
Note that a shared variable guarantees that if two or more threads try to modify it at the same time, the internal state of the variable will not become corrupted. However, there are no guarantees beyond this, as explained in the next section.
So, yes, it is safe to store and fetch simple individual values in a hash without locking.
It's my understanding that whatever locking is necessary to prevent corruption to the internal structure of the hash is handled automatically. The lock
function is to allow threads to coordinate so that the higher-level consistency of the hash can be maintained. Since in this case each key is modified by only one thread, no explicit locking is necessary.
I can't quote an authority, except that I can't find anything in the threads::shared documentation that suggests you need to be careful to lock a variable before modifying it. If doing that could cause Perl to crash, you'd think it would be worth a mention.
IMHO it'll work OK.
threads module docs just mention not to use threads in the END blocks, and do not mention mutexes at all anywhere else besides that. If mutexes were necessary they would for sure be included in the threads module - but they aren't, are they?
my %hash : shared;
map {
async { map { $hash{$_}++; } (1 .. 30); }
} (1 .. 300);
map {$_->join} (threads->list);
print Dumper \%hash;
Each time I run that a get value 300 in each key. So far I couldn't find a better way to prove it's safe.
精彩评论