Class: Farce::ReadWriteLock
- Inherits:
-
Object
- Object
- Farce::ReadWriteLock
- Includes:
- Internal::Copyable, Shareable::Unfreezable, Internal::MarshalSupport::Reject
- Defined in:
- lib/farce/read_write_lock.rb
Overview
A Ractor-shareable read/write lock with fiber-scheduler-aware waiting.
Multiple execution contexts may hold the read lock concurrently. The write lock is exclusive and may be acquired while the current context holds a read lock. One concurrent upgrader retains its read lock continuously. Additional upgraders yield their read slot to avoid deadlock and restore it before returning to the outer read-lock block.
Instance Method Summary collapse
-
#initialize ⇒ ReadWriteLock
constructor
A new instance of ReadWriteLock.
-
#with_read_lock { ... } ⇒ Object
Runs the block while holding a shared read lock.
-
#with_write_lock { ... } ⇒ Object
Runs the block while holding an exclusive write lock.
Methods included from Shareable
Methods included from Internal::Copyable
Constructor Details
#initialize ⇒ ReadWriteLock
Returns a new instance of ReadWriteLock.
32 33 34 35 36 |
# File 'lib/farce/read_write_lock.rb', line 32 def initialize @state = Internal::Vector.new([0]) @signal = Internal::Signal.new super end |
Instance Method Details
#with_read_lock { ... } ⇒ Object
Runs the block while holding a shared read lock.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/farce/read_write_lock.rb', line 42 def with_read_lock raise LocalJumpError, "no block given" unless block_given? local = local_state Thread.handle_interrupt(Internal::INTERRUPT_MASK) do global = local[READ_DEPTH].zero? && local[WRITE_DEPTH].zero? acquire_read_lock if global local[READ_DEPTH] += 1 begin # Block capture allocates on every lock operation. # rubocop:disable-next Style/ExplicitBlockArgument Thread.handle_interrupt(INTERRUPTS_IMMEDIATE) { yield } ensure local[READ_DEPTH] -= 1 release_read_lock if global clear_local_state(local) end end end |
#with_write_lock { ... } ⇒ Object
Runs the block while holding an exclusive write lock.
Calling this method from inside #with_read_lock upgrades the read lock.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/farce/read_write_lock.rb', line 69 def with_write_lock raise LocalJumpError, "no block given" unless block_given? local = local_state Thread.handle_interrupt(Internal::INTERRUPT_MASK) do reentrant = local[WRITE_DEPTH].positive? upgraded = !reentrant && local[READ_DEPTH].positive? acquire_write_lock(upgraded) unless reentrant local[WRITE_DEPTH] += 1 begin # Block capture allocates on every lock operation. # rubocop:disable-next Style/ExplicitBlockArgument Thread.handle_interrupt(INTERRUPTS_IMMEDIATE) { yield } ensure local[WRITE_DEPTH] -= 1 unless reentrant upgraded ? downgrade_write_lock : release_write_lock end clear_local_state(local) end end end |