Class: RWLock
- Inherits:
-
Object
- Object
- RWLock
- Defined in:
- lib/rwlock.rb
Overview
This class provides a simple readers-writer lock (RWLock). A RWLock allows multiple “readers” to access a resource simultaneously but “writers” must have exclusive access. In other words, during a “write” only a single thread may have access to the resource.
This RWLock prevents writer starvation. While there are no hard guarantees, if a writer requests access it will generally get access as soon as all current readers are finished.
When the current writer is finished, waiting readers have first opportunity to grab the lock. This should result in no starvation of either readers nor writers, although access may not be “fair”.
Instance Method Summary collapse
-
#initialize(max_size = 10) ⇒ RWLock
constructor
Creates new readers-writers lock.
-
#max ⇒ Object
Returns the set maximum number of simultaneous readers.
-
#read_sync ⇒ Object
Obtains reading lock and executes block, then releases reading lock.
-
#write_sync ⇒ Object
Obtains writing lock and executes block, then releases writing lock.
Constructor Details
#initialize(max_size = 10) ⇒ RWLock
Creates new readers-writers lock. The ‘max_size` argument limits how many readers may read simultaneously. A limit is necessary to prevent writer starvation.
24 25 26 27 |
# File 'lib/rwlock.rb', line 24 def initialize max_size = 10 @write_lock = Mutex.new @q = SizedQueue.new(max_size) end |
Instance Method Details
#max ⇒ Object
Returns the set maximum number of simultaneous readers.
84 85 86 |
# File 'lib/rwlock.rb', line 84 def max @q.max end |
#read_sync ⇒ Object
Obtains reading lock and executes block, then releases reading lock. Many calls to RWLock#read_sync may execute in parallel, but wil not overlap with calls to RWLock#write_sync.
If the number of readers is currently at the maximum or a write operation is in progress, this method will wait. When a reading spot is available and no write operations are occurring, then the block will be executed.
rwl = RWLock.new
a = [1, 2, 3]
Thread.new do
rwl.read_sync do
puts a[1]
end
end
45 46 47 48 49 50 |
# File 'lib/rwlock.rb', line 45 def read_sync @q.push true yield ensure @q.pop end |
#write_sync ⇒ Object
Obtains writing lock and executes block, then releases writing lock. The block will have exclusive access to the lock, with no readers or other writers allowed to execute at the same time.
If any readers are executing, the method will wait until the current readers are finished then the block will be executed.
If another writer is executing, the method will wait until the current writer is finished. However, readers have first chance at access after a write.
rwl = RWLock.new
a = [1, 2, 3]
Thread.new do
rwl.write_sync do
a[1] += 1
end
end
71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rwlock.rb', line 71 def write_sync @write_lock.synchronize do @q.max.times { @q.push true } begin yield ensure @q.clear end end end |