concurrent-ruby/docs-source/synchronization-notes.md

2.0 KiB

Concurrent Ruby Notes

Locks

Concurrent Ruby also has an internal extension of Object called LockableObject, which provides same synchronization primitives as Java's Object: synchronize(&block), wait(timeout = nil), wait_until(timeout = nil, &condition), signal, broadcast. This class is intended for internal use in concurrent-ruby only and it does not support subclassing (since it cannot protect its lock from its children, for more details see this article). It has minimal interface to be able to use directly locking available on given platforms.

For non-internal use there is Lock and Condition implementation in Synchronization namespace, a condition can be obtained with new_condition method on Lock. So far their implementation is naive and requires more work. API is not expected to change.

Method names conventions

Methods starting with ns_ are marking methods that are not using synchronization by themselves, they have to be used inside synchronize block. They are usually used in pairs to separate the synchronization from behavior and to allow to call methods in the same object without double locking.

class Node
  # ...
  def left
    synchronize { ns_left }
  end  

  def right
    synchronize { ns_right }
  end  

  def to_a
    # avoids double locking
    synchronize { [ns_left, ns_right] }
  end    

  private

  def ns_left
    @left
  end

  def ns_right
    @right
  end
  # ...
end

Piggybacking

Any write executed before volatile write based on program-order is visible to the volatile read as well, which allows piggybacking. Because it creates synchronizes-with (JMM term) order between volatile write and read, which participates in creating happens-before order.

This trick is used in some of the abstractions, to avoid unnecessary synchronization or volatile declarations.