Since you mention the Hash would be read heavy, having one mutex locking both read and writes would result in race conditions that are most probably won by reads. If that's ok with you, then ignore the answer.
If you want to give writes a priority, an read-write lock would help. The following code is based on some old c++ assignment for Operating Systems class, so might not be best quality, but gives a general idea.
require 'thread'
class ReadWriteLock
def initialize
@critical_section = Mutex.new
@are_writers_finished = ConditionVariable.new
@are_readers_finished = ConditionVariable.new
@readers = 0
@writers = 0
@writer_locked = false
end
def read
begin
start_read
yield
ensure
end_read
end
end
def start_read
@critical_section.lock
while (@writers != 0 || @writer_locked)
@are_writers_finished.wait(@critical_section)
end
@readers += 1
@critical_section.unlock
end
def end_read
@critical_section.lock
if (@readers -= 1) == 0
@are_readers_finished.broadcast
end
@critical_section.unlock
end
def write
begin
start_write
yield
ensure
end_write
end
end
def start_write
@critical_section.lock
@writers += 1
while @readers > 0
@are_readers_finished.wait(@critical_section)
end
while @writer_locked
@are_writers_finished.wait(@critical_section)
end
@writers -= 1
@writer_locked = true
@critical_section.unlock
end
def end_write
@critical_section.lock
@writer_locked = false
@are_writers_finished.broadcast
@critical_section.unlock
end
end
Then just wrap []= and [] in lock.write and lock.read. Might have a performance impact, but will guarantee that writes will 'get through' the reads. Usefulness of this depends on how read heavy it actually is.
answered 2009-07-04T09:47:30.070