Class: QuackConcurrency::ReentrantMutex

Inherits:
Mutex
  • Object
show all
Defined in:
lib/quack_concurrency/reentrant_mutex.rb,
lib/quack_concurrency/reentrant_mutex/error.rb

Defined Under Namespace

Classes: Error

Instance Method Summary collapse

Methods inherited from Mutex

#locked?, #owned?, #owner, #waiting_threads_count

Constructor Details

#initializeReentrantMutex

Creates a new QuackConcurrency::ReentrantMutex concurrency tool.



9
10
11
12
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 9

def initialize
  super
  @lock_depth = 0
end

Instance Method Details

#lockvoid #lock { ... } ⇒ Object

Overloads:

  • #lockvoid

    This method returns an undefined value.

    Obtains the lock or sleeps the current ‘Thread` until it is available.

  • #lock { ... } ⇒ Object

    Obtains the lock, runs the block, then releases the lock when the block completes.

    Yields:

    • block to run with the lock

    Returns:

    • (Object)

      result of the block



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 21

def lock(&block)
  if block_given?  
    lock
    start_depth = @lock_depth
    start_owner = owner
    begin
      yield
    ensure
      unless @lock_depth == start_depth && owner == start_owner
        raise Error, 'could not unlock reentrant mutex as its state has been modified'
      end
      unlock
    end
  else
    super unless owned?
    @lock_depth += 1
    nil
  end
end

#locked_out?Boolean

Checks if this QuackConcurrency::ReentrantMutex is locked by a Thread other than the caller.

Returns:

  • (Boolean)


43
44
45
46
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 43

def locked_out?
  # don't need a mutex because we know #owned? can't change during the call 
  locked? && !owned?
end

#sleep(timeout = nil) ⇒ void

This method returns an undefined value.

Releases the lock and sleeps. When the calling Thread is next woken up, it will attempt to reacquire the lock.

Parameters:

  • timeout (Integer) (defaults to: nil)

    seconds to sleep, ‘nil` will sleep forever

Raises:



53
54
55
56
57
58
59
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 53

def sleep(timeout = nil)
  raise Error, 'can not unlock reentrant mutex, it is not locked' unless locked?
  raise Error, 'can not unlock reentrant mutex, caller is not the owner' unless owned?
  base_depth do
    super(timeout)
  end
end

#synchronize(&block) ⇒ Object

Obtains a lock, runs the block, and releases the lock when the block completes.

Returns:

  • (Object)

    value from yielded block



63
64
65
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 63

def synchronize(&block)
  lock(&block)
end

#try_lockBoolean

Attempts to obtain the lock and returns immediately.

Returns:

  • (Boolean)

    returns if the lock was granted



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 71

def try_lock
  if owned?
    @lock_depth += 1
    true
  else
    lock_successful = parent_try_lock
    if lock_successful
      @lock_depth += 1
      true
    else
      false
    end
  end
end

#unlock(&block) ⇒ void

This method returns an undefined value.

Releases the lock.

Raises:



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 89

def unlock(&block)
  raise Error, 'can not unlock reentrant mutex, it is not locked' unless locked?
  raise Error, 'can not unlock reentrant mutex, caller is not the owner' unless owned?
  if block_given?
    unlock
    begin
      yield
    ensure
      lock
    end
  else
    @lock_depth -= 1
    super if @lock_depth == 0
    nil
  end
end

#unlock!(&block) ⇒ void

This method returns an undefined value.

Releases the lock.

Raises:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 109

def unlock!(&block)
  raise Error, 'can not unlock reentrant mutex, it is not locked' unless locked?
  raise Error, 'can not unlock reentrant mutex, caller is not the owner' unless owned?
  if block_given?
    base_depth do
      unlock
      begin
        yield
      ensure
        lock
      end
    end
  else
    @lock_depth = 0
    super
    nil
  end
end