Class: QuackConcurrency::ReentrantMutex

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

Overview

ReentrantMutexs are similar to Mutexs with with the key distinction being that a thread can call lock on a Mutex that it has already locked.

Instance Method Summary collapse

Methods inherited from Mutex

#locked?, #locked_out?, #owned?, #owner, #synchronize, #waiting_threads_count

Constructor Details

#initializeReentrantMutex

Creates a new QuackConcurrency::ReentrantMutex concurrency tool.



12
13
14
15
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 12

def initialize
  super
  @lock_depth = 0
end

Instance Method Details

#lockvoid #lock { ... } ⇒ Object

Overloads:

  • #lockvoid

    This method returns an undefined value.

    Obtains a lock, blocking until available. It will acquire a lock even if one is already held.

  • #lock { ... } ⇒ Object

    Obtains a lock, runs the block, then releases a lock. It will block until a lock is available. It will acquire a lock even if one is already held.

    Yields:

    • block to run with the lock

    Returns:

    • (Object)

      result of the block

    Raises:

    • (ThreadError)

      if not locked by the calling thread when unlocking

    • (ThreadError)

      if not holding the same lock count when unlocking

    • (Exception)

      any exception raised in block



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 30

def lock(&block)
  if block_given?  
    lock
    start_depth = @lock_depth
    begin
      yield
    ensure
      ensure_can_unlock
      unless @lock_depth == start_depth
        raise ThreadError, 'Attempt to unlock a ReentrantMutex whose lock depth has been changed since locking it'
      end
      unlock
    end
  else
    super unless owned?
    @lock_depth += 1
    nil
  end
end

#sleep(timeout = nil) ⇒ Object

See Also:



51
52
53
54
55
56
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 51

def sleep(timeout = nil)
  ensure_can_unlock
  base_depth do
    super(timeout)
  end
end

#try_lockBoolean

Attempts to obtain the lock and returns immediately.

Returns:

  • (Boolean)

    returns if the lock was granted



60
61
62
63
64
65
66
67
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 60

def try_lock
  if owned? || super
    @lock_depth += 1
    true
  else
    false
  end
end

#unlockvoid #unlock { ... } ⇒ Object

Overloads:

  • #unlockvoid

    This method returns an undefined value.

    Releases a lock.

  • #unlock { ... } ⇒ Object

    Releases a lock, runs the block, then reacquires the lock when available,

    blocking if necessary.
    

    Yields:

    • block to run while releasing the lock

    Returns:

    • (Object)

      result of the block

    Raises:

    • (Exception)

      any exception raised in block

    • (ThreadError)

      if relock unsuccessful after an error

Raises:

  • (ThreadError)

    if it is not locked by this thread



80
81
82
83
84
85
86
87
88
89
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 80

def unlock(&block)
  ensure_can_unlock
  if block_given?
    temporarily_release(&block)
  else
    @lock_depth -= 1
    super if @lock_depth == 0
    nil
  end
end

#unlock! { ... } ⇒ Object

Releases all lock, runs the block, then reacquires the same lock count when available,

blocking if necessary.

Yields:

  • block to run while locks have been released

Returns:

  • (Object)

    result of the block

Raises:

  • (ArgumentError)

    if no block given

  • (ThreadError)

    if this thread does not hold any locks

  • (Exception)

    any exception raised in block



98
99
100
101
102
103
# File 'lib/quack_concurrency/reentrant_mutex.rb', line 98

def unlock!(&block)
  ensure_can_unlock
  base_depth do
    temporarily_release(&block)
  end
end