class Concurrent::ReentrantReadWriteLock

def acquire_write_lock

Raises:
  • (Concurrent::ResourceLimitError) - if the maximum number of writers

Returns:
  • (Boolean) - true if the lock is successfully acquired
def acquire_write_lock
  if (held = @HeldCount.value) >= WRITE_LOCK_HELD
    # if we already have a write (exclusive) lock, there's no need to wait
    @HeldCount.value = held + WRITE_LOCK_HELD
    return true
  end
  while true
    c = @Counter.value
    raise ResourceLimitError.new('Too many writer threads') if max_writers?(c)
    # To go ahead and take the lock without waiting, there must be no writer
    #   running right now, AND no writers who came before us still waiting to
    #   acquire the lock
    # Additionally, if any read locks have been taken, we must hold all of them
    if held > 0 && @Counter.compare_and_set(1, c+RUNNING_WRITER)
      # If we are the only one reader and successfully swap the RUNNING_WRITER bit on, then we can go ahead
      @HeldCount.value = held + WRITE_LOCK_HELD
      return true
    elsif @Counter.compare_and_set(c, c+WAITING_WRITER)
      while true
        # Now we have successfully incremented, so no more readers will be able to increment
        #   (they will wait instead)
        # However, readers OR writers could decrement right here
        @WriteQueue.synchronize do
          # So we have to do another check inside the synchronized section
          # If a writer OR another reader is running, then go to sleep
          c = @Counter.value
          @WriteQueue.ns_wait if running_writer?(c) || running_readers(c) != held
        end
        # Note: if you are thinking of replacing the above 'synchronize' block
        # with #wait_until, read the comment in #acquire_read_lock first!
        # We just came out of a wait
        # If we successfully turn the RUNNING_WRITER bit on with an atomic swap,
        #   then we are OK to stop waiting and go ahead
        # Otherwise go back and wait again
        c = @Counter.value
        if !running_writer?(c) &&
           running_readers(c) == held &&
           @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER)
          @HeldCount.value = held + WRITE_LOCK_HELD
          return true
        end
      end
    end
  end
end