class Rex::ReadWriteLock
This class implements a read/write lock synchronization primitive. It is meant to allow for more efficient access to resources that are more often read from than written to and many times can have concurrent reader threads. By allowing the reader threads to lock the resource concurrently rather than serially, a large performance boost can be seen. Acquiring a write lock results in exclusive access to the resource and thereby prevents any read operations during the time that a write lock is acquired. Only one write lock may be acquired at a time.
Public Class Methods
Initializes a reader/writer lock instance.
# File lib/rex/sync/read_write_lock.rb, line 23 def initialize @read_sync_mutex = Mutex.new @write_sync_mutex = Mutex.new @exclusive_mutex = Mutex.new @readers = 0 @writer = false end
Public Instance Methods
Acquires the read lock for the calling thread.
# File lib/rex/sync/read_write_lock.rb, line 34 def lock_read read_sync_mutex.lock begin # If there are a non-zero number of readers and a # writer is waiting to acquire the exclusive lock, # free up the sync mutex temporarily and lock/unlock # the exclusive lock. This is to give the writer # thread a chance to acquire the lock and prevents # it from being constantly starved. if ((@readers > 0) and (@writer)) read_sync_mutex.unlock exclusive_mutex.lock exclusive_mutex.unlock read_sync_mutex.lock end # Increment the active reader count @readers += 1 # If we now have just one reader, acquire the exclusive # lock. Track the thread owner so that we release the # lock from within the same thread context later on. if (@readers == 1) exclusive_mutex.lock @owner = Thread.current end ensure read_sync_mutex.unlock end end
Acquire the exclusive write lock.
# File lib/rex/sync/read_write_lock.rb, line 113 def lock_write write_sync_mutex.lock begin @writer = true exclusive_mutex.lock @owner = Thread.current ensure write_sync_mutex.unlock end end
Synchronize a block for read access.
# File lib/rex/sync/read_write_lock.rb, line 146 def synchronize_read lock_read begin yield ensure unlock_read end end
Synchronize a block for write access.
# File lib/rex/sync/read_write_lock.rb, line 158 def synchronize_write lock_write begin yield ensure unlock_write end end
Releases the read lock for the calling thread.
# File lib/rex/sync/read_write_lock.rb, line 71 def unlock_read read_sync_mutex.lock begin unlocked = false # Keep looping until we've lost this thread's reader # lock while (!unlocked) # If there are no more readers left after this one if (@readers - 1 == 0) # If the calling thread is the owner of the exclusive # reader lock, then let's release it if (Thread.current == @owner) @owner = nil exclusive_mutex.unlock end # If there is more than one reader left and this thread is # the owner of the exclusive lock, then keep looping so that # we can eventually unlock the exclusive mutex in this thread's # context elsif (Thread.current == @owner) read_sync_mutex.unlock next end # Unlocked! unlocked = true # Decrement the active reader count @readers -= 1 end ensure read_sync_mutex.unlock end end
Release the exclusive write lock.
# File lib/rex/sync/read_write_lock.rb, line 130 def unlock_write # If the caller is not the owner of the write lock, then someone is # doing something broken, let's let them know. if (Thread.current != @owner) raise RuntimeError, "Non-owner calling thread attempted to release write lock", caller end # Otherwise, release the exclusive write lock @writer = false exclusive_mutex.unlock end