Spec-Zone.ru › Ruby 3.4

модуль 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, в то время как buf.empty?. Поток-производитель (главный поток) считывает строку из ARGF и добавляет её в buf, затем вызывает 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 реализует Array с синхронизированным доступом к элементам. Этот класс реализован как подкласс Array, который подключает модуль MonitorMixin.

Открытые методы класса

new (...) Показать исходный код
# File ext/monitor/lib/monitor.rb, line 222
def initialize(...)
  super
  mon_initialize
end

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

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

Открытые методы экземпляра

mon_enter () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 169
def mon_enter
  @mon_data.enter
end

Входит в критическую секцию.

mon_exit () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 176
def mon_exit
  mon_check_owner
  @mon_data.exit
end

Выходит из критической секции.

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

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

mon_owned? () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 191
def mon_owned?
  @mon_data.mon_owned?
end

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

mon_synchronize (&b) Показать исходный код
# File ext/monitor/lib/monitor.rb, line 200
def mon_synchronize(&b)
  @mon_data.synchronize(&b)
end

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

Также имеет псевдоним: synchronize
mon_try_enter () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 160
def mon_try_enter
  @mon_data.try_enter
end

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

Также имеет псевдоним: try_mon_enter
new_cond () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 209
def new_cond
  unless defined?(@mon_data)
    mon_initialize
    @mon_initialized_by_new_cond = true
  end
  return ConditionVariable.new(@mon_data)
end

Создаёт новую MonitorMixin::ConditionVariable, связанную с объектом Monitor.

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

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

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

Закрытые методы экземпляра

mon_check_owner () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 243
def mon_check_owner
  @mon_data.mon_check_owner
end

Проверяет, что текущий поток владеет MonitorMixin; в противном случае вызывает исключение.

mon_initialize () Показать исходный код
# File ext/monitor/lib/monitor.rb, line 229
def mon_initialize
  if defined?(@mon_data)
    if defined?(@mon_initialized_by_new_cond)
      return # already initialized.
    elsif @mon_data_owner_object_id == self.object_id
      raise ThreadError, "already initialized"
    end
  end
  @mon_data = ::Monitor.new
  @mon_data_owner_object_id = self.object_id
end

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

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

Spec-Zone.ru

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