Class: ProcessShared::Mutex
- Inherits:
-
Object
- Object
- ProcessShared::Mutex
- Defined in:
- lib/process_shared/mutex.rb
Overview
This Mutex class is implemented as a BoundedSemaphore with a maximum value of 1. Additionally, the locking process is tracked, and ProcessError is raised if either #unlock is called by a process different from the locking process, or if #lock is called while the process already holds the lock (i.e. the mutex is not re-entrant). This tracking is not without performance cost, of course (current implementation uses an additional BoundedSemaphore and SharedMemory segment).
The API is intended to be identical to the ::Mutex in the core Ruby library.
TODO: the core Ruby api has no #close method, but this Mutex must release its BoundedSemaphore and SharedMemory resources. For now, we rely on the object finalizers of those objects…
Instance Method Summary collapse
-
#initialize ⇒ Mutex
constructor
def self.open(&block) new.with_self(&block) end.
- #lock ⇒ Mutex
- #locked? ⇒ Boolean
-
#sleep(timeout = nil) ⇒ Numeric
Releases the lock and sleeps timeout seconds if it is given and non-nil or forever.
-
#synchronize ⇒ Object
Acquire the lock, yield the block, then ensure the lock is unlocked.
- #try_lock ⇒ Boolean
- #unlock ⇒ Mutex
Constructor Details
#initialize ⇒ Mutex
def self.open(&block)
new.with_self(&block)
end
29 30 31 32 33 34 |
# File 'lib/process_shared/mutex.rb', line 29 def initialize @internal_sem = BoundedSemaphore.new(1) @locked_by = SharedMemory.new(:int) @sem = BoundedSemaphore.new(1) end |
Instance Method Details
#lock ⇒ Mutex
37 38 39 40 41 42 43 44 45 |
# File 'lib/process_shared/mutex.rb', line 37 def lock if locked_by == ::Process.pid raise ProcessError, "already locked by this process #{::Process.pid}" end @sem.wait self.locked_by = ::Process.pid self end |
#locked? ⇒ Boolean
48 49 50 |
# File 'lib/process_shared/mutex.rb', line 48 def locked? locked_by > 0 end |
#sleep(timeout = nil) ⇒ Numeric
Releases the lock and sleeps timeout seconds if it is given and non-nil or forever.
56 57 58 59 60 61 62 63 |
# File 'lib/process_shared/mutex.rb', line 56 def sleep(timeout = nil) unlock begin timeout ? Kernel.sleep(timeout) : Kernel.sleep ensure lock end end |
#synchronize ⇒ Object
Acquire the lock, yield the block, then ensure the lock is unlocked.
93 94 95 96 97 98 99 100 |
# File 'lib/process_shared/mutex.rb', line 93 def synchronize lock begin yield ensure unlock end end |
#try_lock ⇒ Boolean
66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/process_shared/mutex.rb', line 66 def try_lock with_internal_lock do if @locked_by.get_int(0) > 0 false # was locked else @sem.wait self.locked_by = ::Process.pid true end end end |
#unlock ⇒ Mutex
79 80 81 82 83 84 85 86 87 |
# File 'lib/process_shared/mutex.rb', line 79 def unlock if (p = locked_by) != ::Process.pid raise ProcessError, "lock is held by #{p} not #{::Process.pid}" end self.locked_by = 0 @sem.post self end |