class ReadWriteLock
Constants
- MAX_READERS
- MAX_WRITERS
- RUNNING_WRITER
- WAITING_WRITER
Public Class Methods
new()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 43 def initialize @counter = Concurrent::Atomic.new(0) # single integer which represents lock state @reader_q = ConditionVariable.new # queue for waiting readers @reader_mutex = Mutex.new # to protect reader queue @writer_q = ConditionVariable.new # queue for waiting writers @writer_mutex = Mutex.new # to protect writer queue end
Public Instance Methods
acquire_read_lock()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 70 def acquire_read_lock loop do c = @counter.value fail 'Too many reader threads!' if (c & MAX_READERS) == MAX_READERS # If a writer is waiting when we first queue up, we need to wait if c >= WAITING_WRITER # But it is possible that the writer could finish and decrement @counter right here... @reader_mutex.synchronize do # So check again inside the synchronized section @reader_q.wait(@reader_mutex) if @counter.value >= WAITING_WRITER end # after a reader has waited once, they are allowed to "barge" ahead of waiting writers # but if a writer is *running*, the reader still needs to wait (naturally) loop do c = @counter.value if c >= RUNNING_WRITER @reader_mutex.synchronize do @reader_q.wait(@reader_mutex) if @counter.value >= RUNNING_WRITER end else return if @counter.compare_and_swap(c, c + 1) end end else break if @counter.compare_and_swap(c, c + 1) end end end
acquire_write_lock()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 114 def acquire_write_lock loop do c = @counter.value fail 'Too many writers!' if (c & MAX_WRITERS) == MAX_WRITERS if c == 0 # no readers OR writers running # if we successfully swap the RUNNING_WRITER bit on, then we can go ahead break if @counter.compare_and_swap(0, RUNNING_WRITER) elsif @counter.compare_and_swap(c, c + WAITING_WRITER) loop do # Now we have successfully incremented, so no more readers will be able to increment # (they will wait instead) # However, readers OR writers could decrement right here, OR another writer could increment @writer_mutex.synchronize do # So we have to do another check inside the synchronized section # If a writer OR reader is running, then go to sleep c = @counter.value @writer_q.wait(@writer_mutex) if (c >= RUNNING_WRITER) || ((c & MAX_READERS) > 0) end # We just came out of a wait # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, # Then we are OK to stop waiting and go ahead # Otherwise go back and wait again c = @counter.value break if (c < RUNNING_WRITER) && ((c & MAX_READERS) == 0) && @counter.compare_and_swap(c, c + RUNNING_WRITER - WAITING_WRITER) end break end end end
release_read_lock()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 101 def release_read_lock loop do c = @counter.value if @counter.compare_and_swap(c, c - 1) # If one or more writers were waiting, and we were the last reader, wake a writer up if c >= WAITING_WRITER && (c & MAX_READERS) == 1 @writer_mutex.synchronize { @writer_q.signal } end break end end end
release_write_lock()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 148 def release_write_lock loop do c = @counter.value if @counter.compare_and_swap(c, c - RUNNING_WRITER) @reader_mutex.synchronize { @reader_q.broadcast } @writer_mutex.synchronize { @writer_q.signal } if (c & MAX_WRITERS) > 0 # if any writers are waiting... break end end end
to_s()
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 159 def to_s c = @counter.value s = if c >= RUNNING_WRITER '1 writer running, ' elsif (c & MAX_READERS) > 0 "#{c & MAX_READERS} readers running, " else '' end "#<ReadWriteLock:#{object_id.to_s(16)} #{s}#{(c & MAX_WRITERS) / WAITING_WRITER} writers waiting>" end
with_read_lock() { || ... }
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 56 def with_read_lock acquire_read_lock result = yield release_read_lock result end
with_write_lock() { || ... }
click to toggle source
# File lib/volt/utils/read_write_lock.rb, line 63 def with_write_lock acquire_write_lock result = yield release_write_lock result end