`Concurrent::Hash` default initialization is not fully thread-safe
@eregon ci sta già lavorando.
Dal 12/12/2022.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Based on the docs:
A thread-safe subclass of Hash. This version locks against the object itself for every method call, ensuring only one thread can be reading or writing at a time. This includes iteration methods like #each, which takes the lock repeatedly when reading an item.
Given this code:
h = Concurrent::Hash.new do |hash, key|
hash[key] = Concurrent::Array.new
end
the initialization is not thread-safe.
Note from @eregon, the thread-safe variant of this code is:
h = Concurrent::Map.new do |hash, key|
hash.compute_if_absent(key) { Concurrent::Array.new }
end
Obviously the latter part of the doc indicates that:
ensuring only one thread can be reading or writing at a time
but the initial part makes it confusing:
This version locks against the object itself for every method call
It can be demoed by running this code:
require 'concurrent-ruby'
1000.times do
h = Concurrent::Hash.new do |hash, key|
hash[key] = Concurrent::Array.new
end
100.times.map do
Thread.new do
h[:na] << true
end
end.each(&:join)
raise if h[:na].count != 100
end
I would expect to either:
- Have the initialization block behind a mutex - so there is no conflict
- Have the docs updated (I can do that)
Works like so:
require 'concurrent-ruby'
m = Mutex.new
1000.times do
h = Concurrent::Hash.new do |hash, key|
m.synchronize do
break hash[key] if hash.key?(key)
hash[key] = Concurrent::Array.new
end
end
100.times.map do
Thread.new do
h[:na] << true
end
end.each(&:join)
raise if h[:na].count != 100
end
- Lingua principale
- Ruby
- Stelle
- 5.8k
- Fork
- 420
- Merge medio
- 20h 45m
- PR unite (30g)
- 4
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ruby-concurrency/concurrent-ruby
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
ruby-concurrency/concurrent-ruby#1118 ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
ruby-concurrency/concurrent-ruby#1099 · 9 commenti ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
ruby-concurrency/concurrent-ruby#1095 · 8 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
ruby-concurrency/concurrent-ruby#1093 · 3 commenti ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 45/100
ruby-concurrency/concurrent-ruby#1091 ·