Spec-Zone.ru › Ruby on Rails 5.0

класс ActiveSupport::Concurrency::ShareLock

Родитель:
Объект
Включённые модули:

Блокировка с совместным/исключительным доступом, иначе известная как блокировка с чтением/записью.

en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

Публичные методы класса

new() Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 49
def initialize
  super()

  @cv = new_cond

  @sharing = Hash.new(0)
  @waiting = {}
  @sleeping = {}
  @exclusive_thread = nil
  @exclusive_depth = 0
end
Вызывает метод суперкласса

Публичные методы экземпляра

exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false) { || ... } Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 147
def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
  if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
    begin
      yield
    ensure
      stop_exclusive(compatible: after_compatible)
    end
  end
end

Выполняет переданный блок, удерживая эксклюзивную блокировку. Если no_wait установлено и блокировка не доступна сразу, возвращает nil, не уступая. В противном случае возвращает результат блока.

См. start_exclusive для других вариантов.

sharing() { || ... } Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 158
def sharing
  start_sharing
  begin
    yield
  ensure
    stop_sharing
  end
end

Выполняет переданный блок, удерживая общую блокировку.

start_exclusive(purpose: nil, compatible: [], no_wait: false) Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 75
def start_exclusive(purpose: nil, compatible: [], no_wait: false)
  synchronize do
    unless @exclusive_thread == Thread.current
      if busy_for_exclusive?(purpose)
        return false if no_wait

        yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
          wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
        end
      end
      @exclusive_thread = Thread.current
    end
    @exclusive_depth += 1

    true
  end
end

Возвращает false, если no_wait установлено и блокировка не доступна сразу. В противном случае возвращает true после получения блокировки.

purpose и compatible работают вместе; в то время как этот поток ожидает эксклюзивной блокировки, он уступит свою общую (если есть) любой другой попытке, чьё purpose появляется в списке compatible этой попытки. Это позволяет «мягкое» обновление, которое, будучи менее строгим, предотвращает некоторые типы тупиков.

Для многих ресурсов мягкие обновления достаточны: если поток ожидает блокировку, он не выполняет никакой другой код. С purpose сопоставлением, можно уступить только другим потокам, чья активность не будет создавать конфликтов.

start_sharing() Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 113
def start_sharing
  synchronize do
    if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
      # We already hold a lock; nothing to wait for
    elsif @waiting[Thread.current]
      # We're nested inside a +yield_shares+ call: we'll resume as
      # soon as there isn't an exclusive lock in our way
      wait_for(:start_sharing) { @exclusive_thread }
    else
      # This is an initial / outermost share call: any outstanding
      # requests for an exclusive lock get to go first
      wait_for(:start_sharing) { busy_for_sharing?(false) }
    end
    @sharing[Thread.current] += 1
  end
end
stop_exclusive(compatible: []) Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 95
def stop_exclusive(compatible: [])
  synchronize do
    raise "invalid unlock" if @exclusive_thread != Thread.current

    @exclusive_depth -= 1
    if @exclusive_depth == 0
      @exclusive_thread = nil

      if eligible_waiters?(compatible)
        yield_shares(compatible: compatible, block_share: true) do
          wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
        end
      end
      @cv.broadcast
    end
  end
end

Освободить эксклюзивную блокировку. Должен вызываться только потоком, который вызвал #start_exclusive (и в настоящее время удерживает блокировку).

stop_sharing() Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 130
def stop_sharing
  synchronize do
    if @sharing[Thread.current] > 1
      @sharing[Thread.current] -= 1
    else
      @sharing.delete Thread.current
      @cv.broadcast
    end
  end
end
yield_shares(purpose: nil, compatible: [], block_share: false) { || ... } Показать исходный код
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 170
def yield_shares(purpose: nil, compatible: [], block_share: false)
  loose_shares = previous_wait = nil
  synchronize do
    if loose_shares = @sharing.delete(Thread.current)
      if previous_wait = @waiting[Thread.current]
        purpose = nil unless purpose == previous_wait[0]
        compatible &= previous_wait[1]
      end
      compatible |= [false] unless block_share
      @waiting[Thread.current] = [purpose, compatible]
    end

    @cv.broadcast
  end

  begin
    yield
  ensure
    synchronize do
      wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }

      if previous_wait
        @waiting[Thread.current] = previous_wait
      else
        @waiting.delete Thread.current
      end
      @sharing[Thread.current] = loose_shares if loose_shares
    end
  end
end

Временно отказаться от всех удерживаемых общих блокировок во время выполнения переданного блока, позволяя любой compatible запросу на эксклюзивную блокировку продолжить.

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API