Class: Gin::RWLock
- Inherits:
-
Object
- Object
- Gin::RWLock
- Defined in:
- lib/gin/rw_lock.rb
Overview
Read-Write lock pair for accessing data that is mostly read-bound. Reading is done without locking until a write operation is started.
lock = Gin::RWLock.new
lock.write_sync{ write_to_the_object }
value = lock.read_sync{ read_from_the_object }
The RWLock is built to work primarily in Thread-pool type environments and its effectiveness is much less for Thread-spawn models.
RWLock also shows increased performance in GIL-less Ruby implementations such as Rubinius 2.x.
Using write_sync from inside a read_sync block is safe, but the inverse isn’t:
lock = Gin::RWLock.new
# This is OK.
lock.read_sync do
get_value || lock.write_sync{ update_value }
end
# This is NOT OK and will raise a ThreadError.
# It's also not necessary because read sync-ing is inferred
# during write syncs.
lock.write_sync do
update_value
lock.read_sync{ get_value }
end
Defined Under Namespace
Classes: WriteTimeout
Constant Summary collapse
- TIMEOUT_MSG =
"Took too long to lock all config mutexes. \ Try increasing the value of write_timeout."
Instance Attribute Summary collapse
-
#write_timeout ⇒ Object
The amount of time to wait for writer threads to get all the read locks.
Instance Method Summary collapse
-
#initialize(write_timeout = nil) ⇒ RWLock
constructor
A new instance of RWLock.
- #read_sync ⇒ Object
- #write_sync ⇒ Object
Constructor Details
#initialize(write_timeout = nil) ⇒ RWLock
Returns a new instance of RWLock.
43 44 45 46 47 48 49 |
# File 'lib/gin/rw_lock.rb', line 43 def initialize write_timeout=nil @wmutex = Mutex.new @write_timeout = write_timeout || 0.05 @mutex_id = :"rwlock_#{self.object_id}" @mutex_owned_id = :"#{@mutex_id}_owned" @rmutex_owned_id = :"#{@mutex_id}_r_owned" end |
Instance Attribute Details
#write_timeout ⇒ Object
The amount of time to wait for writer threads to get all the read locks.
40 41 42 |
# File 'lib/gin/rw_lock.rb', line 40 def write_timeout @write_timeout end |
Instance Method Details
#read_sync ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/gin/rw_lock.rb', line 81 def read_sync was_locked = Thread.current[@rmutex_owned_id] unless was_locked read_mutex.lock Thread.current[@rmutex_owned_id] = true end yield ensure if !was_locked Thread.current[@rmutex_owned_id] = false read_mutex.unlock end end |
#write_sync ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/gin/rw_lock.rb', line 52 def write_sync lock_mutexes = [] was_locked = Thread.current[@mutex_owned_id] write_mutex.lock unless was_locked Thread.current[@mutex_owned_id] = true start = Time.now Thread.list.each do |t| mutex = t[@mutex_id] next if !mutex || t == Thread.current until mutex.try_lock Thread.pass raise WriteTimeout, TIMEOUT_MSG if Time.now - start > @write_timeout end lock_mutexes << mutex end yield ensure lock_mutexes.each(&:unlock) unless was_locked Thread.current[@mutex_owned_id] = false write_mutex.unlock end end |