模块 MonitorMixin

在并发编程中,监视器是一个对象或模块,旨在被多个线程安全地使用。监视器的定义特征是其方法以互斥方式执行。也就是说,在任何时间点,最多只有一个线程可以执行其任何方法。与推理更新数据结构的并行代码相比,这种互斥极大地简化了对监视器实现的推理。

您可以在维基百科页面上阅读有关一般原则的更多信息 监视器.

示例

简单对象.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 通知消费者线程有新数据。

简单 Class 包含

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 模块。

公共类方法

extend_object(obj) 点击切换源代码
调用超类方法
# File ext/monitor/lib/monitor.rb, line 152
def self.extend_object(obj)
  super(obj)
  obj.__send__(:mon_initialize)
end
new(...) 点击切换源代码

使用 extend MonitorMixininclude MonitorMixin 而不是此构造函数。查看上面的示例以了解如何使用此模块。

调用超类方法
# File ext/monitor/lib/monitor.rb, line 222
def initialize(...)
  super
  mon_initialize
end

公共实例方法

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?() 点击切换源代码

如果此监视器被任何线程锁定,则返回 true

# File ext/monitor/lib/monitor.rb, line 184
def mon_locked?
  @mon_data.mon_locked?
end
mon_owned?() 点击切换源代码

如果此监视器被当前线程锁定,则返回 true。

# File ext/monitor/lib/monitor.rb, line 191
def mon_owned?
  @mon_data.mon_owned?
end
mon_synchronize(&b) 点击切换源代码

进入排他部分并执行代码块。代码块退出时,会自动离开排他部分。请参阅 MonitorMixin 中的示例。

# File ext/monitor/lib/monitor.rb, line 200
def mon_synchronize(&b)
  @mon_data.synchronize(&b)
end
别名:synchronize
mon_try_enter() 点击切换源代码

尝试进入排他部分。如果锁定失败,则返回 false

# File ext/monitor/lib/monitor.rb, line 160
def mon_try_enter
  @mon_data.try_enter
end
别名:try_mon_enter
new_cond() 点击切换源代码

创建一个新的 MonitorMixin::ConditionVariable,与 Monitor 对象相关联。

# 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
synchronize(&b)
别名:mon_synchronize
try_mon_enter()

为了向后兼容

别名:mon_try_enter

私有实例方法

mon_check_owner() 点击切换源代码
# File ext/monitor/lib/monitor.rb, line 241
def mon_check_owner
  @mon_data.mon_check_owner
end
mon_initialize() 点击切换源代码

在将 MonitorMixin 包含到类中或用 MonitorMixin 扩展对象后初始化 MonitorMixin

# 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