Spec-Zone.ru › Ruby 2.5

Модуль MonitorMixin

В конкурентном программировании монитор — это объект или модуль, предназначенный для безопасного использования более чем одной нитью. Определяющей характеристикой монитора является то, что его методы выполняются с взаимным исключением. То есть в любой момент времени не более одной нити может выполнять любой из его методов. Это взаимное исключение значительно упрощает понимание реализации мониторов по сравнению с параллельным кодом, обновляющим структуру данных.

Подробнее об общих принципах можно прочитать на странице Википедии для мониторов

Примеры

Простой object.extend

require 'monitor.rb'

buf = []
buf.extend(MonitorMixin)
empty_cond = buf.new_cond

# consumer
Thread.start do
  loop do
    buf.synchronize do
      empty_cond.wait_while { buf.empty? }
      print buf.shift
    end
  end
end

# producer
while line = ARGF.gets
  buf.synchronize do
    buf.push(line)
    empty_cond.signal
  end
end

Поток-потребитель ожидает, пока поток-производитель не запишет строку в буфер, в то время как buf.empty?. Поток-производитель (главный поток) считывает строку из ARGF и записывает ее в буфер, затем вызывает empty_cond.signal для уведомления потока-потребителя о новых данных.

Простой включение класса

require 'monitor'

class SynchronizedArray < Array

  include MonitorMixin

  def initialize(*args)
    super(*args)
  end

  alias :old_shift :shift
  alias :old_unshift :unshift

  def shift(n=1)
    self.synchronize do
      self.old_shift(n)
    end
  end

  def unshift(item)
    self.synchronize do
      self.old_unshift(item)
    end
  end

  # other methods ...
end

SynchronizedArray реализует массив с синхронизированным доступом к элементам. Этот класс реализован как подкласс массива, который включает модуль MonitorMixin.

Методы публичного класса

extend_object(obj) Показать исходный код
# File lib/monitor.rb, line 157
def self.extend_object(obj)
  super(obj)
  obj.__send__(:mon_initialize)
end
Вызов метода суперкласса
new(*args) Показать исходный код
# File lib/monitor.rb, line 245
def initialize(*args)
  super
  mon_initialize
end

Используйте extend MonitorMixin или include MonitorMixin вместо этого конструктора. Посмотрите примеры выше, чтобы понять, как использовать этот модуль.

Вызов метода суперкласса

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

mon_enter() Показать исходный код
# File lib/monitor.rb, line 182
def mon_enter
  if @mon_owner != Thread.current
    @mon_mutex.lock
    @mon_owner = Thread.current
    @mon_count = 0
  end
  @mon_count += 1
end

Вход в защищенную секцию.

mon_exit() Показать исходный код
# File lib/monitor.rb, line 194
def mon_exit
  mon_check_owner
  @mon_count -=1
  if @mon_count == 0
    @mon_owner = nil
    @mon_mutex.unlock
  end
end

Выход из защищенной секции.

mon_locked?() Показать исходный код
# File lib/monitor.rb, line 206
def mon_locked?
  @mon_mutex.locked?
end

Возвращает true, если этот монитор заблокирован какой-либо нитью

mon_owned?() Показать исходный код
# File lib/monitor.rb, line 213
def mon_owned?
  @mon_mutex.locked? && @mon_owner == Thread.current
end

Возвращает true, если этот монитор заблокирован текущей нитью.

mon_synchronize() { || ... } Показать исходный код
# File lib/monitor.rb, line 222
def mon_synchronize
  mon_enter
  begin
    yield
  ensure
    mon_exit
  end
end

Входит в защищенную секцию и выполняет блок. Выходит из защищенной секции автоматически при выходе из блока. См. пример в MonitorMixin.

Также известен как: synchronize
mon_try_enter() Показать исходный код
# File lib/monitor.rb, line 165
def mon_try_enter
  if @mon_owner != Thread.current
    unless @mon_mutex.try_lock
      return false
    end
    @mon_owner = Thread.current
    @mon_count = 0
  end
  @mon_count += 1
  return true
end

Попытка входа в защищенную секцию. Возвращает false если блокировка не удается.

Также известен как: try_mon_enter
new_cond() Показать исходный код
# File lib/monitor.rb, line 236
def new_cond
  return ConditionVariable.new(self)
end

Создает новую MonitorMixin::ConditionVariable, связанную с получателем.

synchronize()
Псевдоним для: mon_synchronize
try_mon_enter()

Для обратной совместимости

Псевдоним для: mon_try_enter

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

mon_check_owner() Показать исходный код
# File lib/monitor.rb, line 258
def mon_check_owner
  if @mon_owner != Thread.current
    raise ThreadError, "current thread not owner"
  end
end
mon_enter_for_cond(count) Показать исходный код
# File lib/monitor.rb, line 264
def mon_enter_for_cond(count)
  @mon_owner = Thread.current
  @mon_count = count
end
mon_exit_for_cond() Показать исходный код
# File lib/monitor.rb, line 269
def mon_exit_for_cond
  count = @mon_count
  @mon_owner = nil
  @mon_count = 0
  return count
end
mon_initialize() Показать исходный код
# File lib/monitor.rb, line 252
def mon_initialize
  @mon_owner = nil
  @mon_count = 0
  @mon_mutex = Thread::Mutex.new
end

Инициализирует MonitorMixin после включения в класс или при расширении объекта с помощью MonitorMixin

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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