модуль 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 для уведомления потока-потребителя о новых данных.
Простой Class include
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 с синхронизированным доступом к элементам. Этот Class реализован как подкласс Array, который включает модуль MonitorMixin.
Методы публичного класса
# File lib/monitor.rb, line 162 def self.extend_object(obj) super(obj) obj.__send__(:mon_initialize) end
# File lib/monitor.rb, line 250 def initialize(*args) super mon_initialize end
Используйте extend MonitorMixin или include MonitorMixin вместо этого конструктора. Обратите внимание на примеры выше, чтобы понять, как использовать этот модуль.
Методы публичного экземпляра
# File lib/monitor.rb, line 187
def mon_enter
if @mon_owner != Thread.current
@mon_mutex.lock
@mon_owner = Thread.current
@mon_count = 0
end
@mon_count += 1
end Входит в эксклюзивную секцию.
# File lib/monitor.rb, line 199
def mon_exit
mon_check_owner
@mon_count -=1
if @mon_count == 0
@mon_owner = nil
@mon_mutex.unlock
end
end Выходит из эксклюзивной секции.
# File lib/monitor.rb, line 211 def mon_locked? @mon_mutex.locked? end
Возвращает true, если этот монитор заблокирован какой-либо нитью
# File lib/monitor.rb, line 218 def mon_owned? @mon_mutex.locked? && @mon_owner == Thread.current end
Возвращает true, если этот монитор заблокирован текущей нитью.
# File lib/monitor.rb, line 227
def mon_synchronize
mon_enter
begin
yield
ensure
mon_exit
end
end Входит в эксклюзивную секцию и выполняет блок. Выходит из эксклюзивной секции автоматически при выходе из блока. См. пример в MonitorMixin.
# File lib/monitor.rb, line 170
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 если блокировка не удалась.
# File lib/monitor.rb, line 241 def new_cond return ConditionVariable.new(self) end
Создаёт новый MonitorMixin::ConditionVariable связанный с получателем.
Приватные методы экземпляра
# File lib/monitor.rb, line 267
def mon_check_owner
if @mon_owner != Thread.current
raise ThreadError, "current thread not owner"
end
end # File lib/monitor.rb, line 273 def mon_enter_for_cond(count) @mon_owner = Thread.current @mon_count = count end
# File lib/monitor.rb, line 278 def mon_exit_for_cond count = @mon_count @mon_owner = nil @mon_count = 0 return count end
# File lib/monitor.rb, line 257
def mon_initialize
if defined?(@mon_mutex) && @mon_mutex_owner_object_id == object_id
raise ThreadError, "already initialized"
end
@mon_mutex = Thread::Mutex.new
@mon_mutex_owner_object_id = object_id
@mon_owner = nil
@mon_count = 0
end Инициализирует MonitorMixin после включения в класс или когда объект был расширен с помощью MonitorMixin
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.