Class: ProcessShared::Mutex

Inherits:
Object
  • Object
show all
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

Monitor

Instance Method Summary collapse

Methods included from OpenWithSelf

open

Constructor Details

#initializeMutex

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

#lockMutex

Returns:



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

Returns:

  • (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.

Returns:

  • (Numeric)


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

#synchronizeObject

Acquire the lock, yield the block, then ensure the lock is unlocked.

Returns:

  • (Object)

    the result of the block



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_lockBoolean

Returns:

  • (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

#unlockMutex

Returns:



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