Class: ProcessShared::Mutex
- Inherits:
-
Object
- Object
- ProcessShared::Mutex
- Extended by:
- OpenWithSelf
- Defined in:
- lib/process_shared/mutex.rb
Overview
This Mutex class is implemented as a Semaphore with a second internal Semaphore used to track the locking process is tracked. 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 the additional Semaphore 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 Semaphore and SharedMemory resources. For now, rely on the object finalizers of those objects…
Direct Known Subclasses
Instance Method Summary collapse
-
#initialize ⇒ Mutex
constructor
A new instance of Mutex.
- #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
Methods included from OpenWithSelf
Constructor Details
#initialize ⇒ Mutex
Returns a new instance of Mutex.
24 25 26 27 28 29 |
# File 'lib/process_shared/mutex.rb', line 24 def initialize @internal_sem = Semaphore.new @locked_by = SharedMemory.new(:int) @sem = Semaphore.new end |
Instance Method Details
#lock ⇒ Mutex
32 33 34 35 36 37 38 39 40 |
# File 'lib/process_shared/mutex.rb', line 32 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
43 44 45 |
# File 'lib/process_shared/mutex.rb', line 43 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.
51 52 53 54 55 56 57 58 |
# File 'lib/process_shared/mutex.rb', line 51 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.
88 89 90 91 92 93 94 95 |
# File 'lib/process_shared/mutex.rb', line 88 def synchronize lock begin yield ensure unlock end end |
#try_lock ⇒ Boolean
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/process_shared/mutex.rb', line 61 def try_lock with_internal_lock do if @locked_by.get_int(0) > 0 false # was locked else @sem.wait # should return immediately self.locked_by = ::Process.pid true end end end |
#unlock ⇒ Mutex
74 75 76 77 78 79 80 81 82 |
# File 'lib/process_shared/mutex.rb', line 74 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 |