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 and thread.
ProcessError is raised if either #unlock is called by a process + thread different from the locking process + thread, or if #lock is called while the process + thread 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.
25 26 27 28 29 30 |
# File 'lib/process_shared/mutex.rb', line 25 def initialize @internal_sem = Semaphore.new @locked_by = SharedMemory.new(:uint64, 2) # [Process ID, Thread ID] @sem = Semaphore.new end |
Instance Method Details
#lock ⇒ Mutex
33 34 35 36 37 38 39 40 41 |
# File 'lib/process_shared/mutex.rb', line 33 def lock if (p, t = current_process_and_thread) == locked_by raise ProcessError, "already locked by this process #{p}, thread #{t}" end @sem.wait self.locked_by = current_process_and_thread self end |
#locked? ⇒ Boolean
44 45 46 |
# File 'lib/process_shared/mutex.rb', line 44 def locked? locked_by != UNLOCKED end |
#sleep(timeout = nil) ⇒ Numeric
Releases the lock and sleeps timeout seconds if it is given and non-nil or forever.
52 53 54 55 56 57 58 59 |
# File 'lib/process_shared/mutex.rb', line 52 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.
89 90 91 92 93 94 95 96 |
# File 'lib/process_shared/mutex.rb', line 89 def synchronize lock begin yield ensure unlock end end |
#try_lock ⇒ Boolean
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/process_shared/mutex.rb', line 62 def try_lock with_internal_lock do if locked? false # was locked else @sem.wait # should return immediately self.locked_by = current_process_and_thread true end end end |
#unlock ⇒ Mutex
75 76 77 78 79 80 81 82 83 |
# File 'lib/process_shared/mutex.rb', line 75 def unlock if (p, t = locked_by) != (cp, ct = current_process_and_thread) raise ProcessError, "lock is held by process #{p}, thread #{t}: not process #{cp}, thread #{ct}" end self.locked_by = UNLOCKED @sem.post self end |