Class: Rex::ReadWriteLock
- Inherits:
-
Object
- Object
- Rex::ReadWriteLock
- Defined in:
- lib/rex/sync/read_write_lock.rb
Overview
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.
Instance Method Summary collapse
-
#initialize ⇒ ReadWriteLock
constructor
Initializes a reader/writer lock instance.
-
#lock_read ⇒ Object
Acquires the read lock for the calling thread.
-
#lock_write ⇒ Object
Acquire the exclusive write lock.
-
#synchronize_read ⇒ Object
Synchronize a block for read access.
-
#synchronize_write ⇒ Object
Synchronize a block for write access.
-
#unlock_read ⇒ Object
Releases the read lock for the calling thread.
-
#unlock_write ⇒ Object
Release the exclusive write lock.
Constructor Details
#initialize ⇒ ReadWriteLock
Initializes a reader/writer lock instance.
24 25 26 27 28 29 30 |
# File 'lib/rex/sync/read_write_lock.rb', line 24 def initialize @read_sync_mutex = Mutex.new @write_sync_mutex = Mutex.new @exclusive_mutex = Mutex.new @readers = 0 @writer = false end |
Instance Method Details
#lock_read ⇒ Object
Acquires the read lock for the calling thread.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rex/sync/read_write_lock.rb', line 35 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 |
#lock_write ⇒ Object
Acquire the exclusive write lock.
114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/rex/sync/read_write_lock.rb', line 114 def lock_write write_sync_mutex.lock begin @writer = true exclusive_mutex.lock @owner = Thread.current ensure write_sync_mutex.unlock end end |
#synchronize_read ⇒ Object
Synchronize a block for read access.
147 148 149 150 151 152 153 154 |
# File 'lib/rex/sync/read_write_lock.rb', line 147 def synchronize_read lock_read begin yield ensure unlock_read end end |
#synchronize_write ⇒ Object
Synchronize a block for write access.
159 160 161 162 163 164 165 166 |
# File 'lib/rex/sync/read_write_lock.rb', line 159 def synchronize_write lock_write begin yield ensure unlock_write end end |
#unlock_read ⇒ Object
Releases the read lock for the calling thread.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rex/sync/read_write_lock.rb', line 72 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 |
#unlock_write ⇒ Object
Release the exclusive write lock.
131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/rex/sync/read_write_lock.rb', line 131 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 |