Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kind fetcher locks are not fully thread-safe
In case of extensive concurrent usage, the mutex handed over to two threads under same key may differ as illustrated below: ```ruby require 'concurrent' 10000.times do kind_fetcher_locks = Concurrent::Hash.new { |hash, key| hash[key] = Mutex.new } refs = Set.new 100.times.map do |i| Thread.new { refs << kind_fetcher_locks[i % 50].object_id } end.each(&:join) raise "Not 50 but #{refs.count}" unless refs.size == 50 end ``` this can lead to really weird issues. Works when fixed as above: ```ruby require 'concurrent' 10000.times do mutex = Mutex.new # kind_fetcher_locks = Concurrent::Hash.new { |hash, key| hash[key] = Mutex.new } kind_fetcher_locks = Concurrent::Hash.new do |hash, key| mutex.synchronize do break hash[key] if hash.key?(key) hash[key] = Mutex.new end end refs = Set.new 100.times.map do |i| Thread.new { refs << kind_fetcher_locks[i % 50].object_id } end.each(&:join) raise "Not 50 but #{refs.count}" unless refs.size == 50 end ``` ref ruby-concurrency/concurrent-ruby#970
- Loading branch information