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 Config#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 |
# 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" 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
88 89 90 91 92 93 94 |
# File 'lib/gin/rw_lock.rb', line 88 def read_sync was_locked = read_mutex.locked? read_mutex.lock unless was_locked yield ensure read_mutex.unlock if was_locked end |
#write_sync ⇒ Object
51 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 79 80 81 82 83 84 85 |
# File 'lib/gin/rw_lock.rb', line 51 def write_sync lock_mutexes = [] relock_curr = false was_locked = Thread.current[@mutex_owned_id] curr_mutex = read_mutex write_mutex.lock unless was_locked Thread.current[@mutex_owned_id] = true # Protect against same-thread deadlocks if curr_mutex && curr_mutex.locked? relock_curr = curr_mutex.unlock rescue false end start = Time.now Thread.list.each do |t| mutex = t[@mutex_id] next if !mutex || !relock_curr && t == Thread.current until mutex.try_lock raise WriteTimeout, TIMEOUT_MSG if Time.now - start > @write_timeout end lock_mutexes << mutex end yield ensure lock_mutexes.each(&:unlock) curr_mutex.try_lock if relock_curr unless was_locked Thread.current[@mutex_owned_id] = false write_mutex.unlock end end |