模組 MonitorMixin

在並行程式設計中,監視器是一個物件或模組,旨在讓多個執行緒安全地使用。監視器的定義特性是其方法以互斥方式執行。也就是說,在每個時間點,最多只有一個執行緒可以執行其任何方法。與推理更新資料結構的平行程式碼相比,這種互斥極大地簡化了對監視器實作的推理。

您可以在 Wikipedia 的 監視器 頁面上閱讀有關一般原理的更多資訊。

範例

簡單的物件.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 以通知消費者執行緒有新資料。

簡單的 類別 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 實作一個 陣列,其中包含對項目進行同步存取。此 類別 實作為 陣列 的子類別,其中包含 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

# 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