Class: ProcessShared::Mutex

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

Instance Method Summary collapse

Constructor Details

#initializeMutex

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 = Semaphore.new
  @locked_by = SharedMemory.new(:int)

  @sem = Semaphore.new
end

Instance Method Details

#lockMutex

Returns:



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

Returns:

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

Returns:

  • (Numeric)


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

#synchronizeObject

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

Returns:

  • (Object)

    the result of the block



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_lockBoolean

Returns:

  • (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             # should return immediately
      self.locked_by = ::Process.pid
      true
    end
  end
end

#unlockMutex

Returns:



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