Ruby 1.8.7 リファレンスマニュアル > ライブラリ一覧 > threadライブラリ > ConditionVariableクラス

class ConditionVariable

クラスの継承リスト: ConditionVariable < Object < Kernel

要約

スレッドの同期機構の一つである状態変数を実現するクラスです。

以下も ConditionVariable を理解するのに参考になります。

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html#UF

Condition Variable とは

あるスレッド A が排他領域で動いていたとします。スレッド A は現在空いていない リソースが必要になったので空くまで待つことにしたとします。これはうまくいきません。 なぜなら、スレッド A は排他領域で動いているわけですから、他のスレッドは動くことが できません。リソースを空けることもできません。スレッド A がリソースの空きを 待っていても、いつまでも空くことはありません。

以上のような状況を解決するのが Condition Variable です。

スレッド a で条件(リソースが空いているかなど)が満たされるまで wait メソッドで スレッドを止めます。他のスレッド b において条件が満たされたなら signal メソッドでスレッド a に対して条件が成立したことを通知します。これが典型^な 使用例です。

mutex = Mutex.new
cv = ConditionVariable.new

a = Thread.start {
    mutex.synchronize {
      ...
      while (条件が満たされない)
        cv.wait(mutex)
      end
      ...
    }
}

b = Thread.start {
    mutex.synchronize {
      # 上の条件を満たすための操作
      cv.signal
    }
}

以下は [ruby-list:14445] で紹介されている例です。@q が空になった場合、 あるいは満たんになった場合に Condition Variable を使って wait しています。

require 'thread'

class TinyQueue
  def initialize(max=2)
    @max = max
    @full = ConditionVariable.new
    @empty = ConditionVariable.new
    @mutex = Mutex.new
    @q = []
  end

  def count
    @q.size
  end

  def enq(v)
    @mutex.synchronize{
      @full.wait(@mutex) if count == @max
      @q.push v
      @empty.signal if count == 1
    }
  end

  def deq
    @mutex.synchronize{
      @empty.wait(@mutex) if count == 0
      v = @q.shift
      @full.signal if count == (@max - 1)
      v
    }
  end

  alias send enq
  alias recv deq
end

if __FILE__ == $0
  q = TinyQueue.new(1)
  foods = 'Apple Banana Strawberry Udon Rice Milk'.split
  l = []

  th = Thread.new {
    for obj in foods
      q.send(obj)
      print "sent ", obj, "\n"
    end
    q.send nil
  }

  l.push th

  th = Thread.new {
    while obj = q.recv
      print "recv ", obj, "\n"
    end
  }
  l.push th

  l.each do |t|
    t.join
  end
end

実行すると以下のように出力します。

$ ruby condvar.rb
sent Apple
recv Apple
sent Banana
recv Banana
sent Strawberry
recv Strawberry
sent Udon
recv Udon
sent Rice
recv Rice
sent Milk
recv Milk

特異メソッド

定義 説明
new

状態変数を生成して返します。

インスタンスメソッド

定義 説明
broadcast

状態変数を待っているスレッドをすべて再開します。再開された スレッドは ConditionVariable#wait で指定した mutex のロックを試みます。

signal

状態変数を待っているスレッドを1つ再開します。再開された スレッドは ConditionVariable#wait で指定した mutex のロックを試みます。

wait(mutex)

mutex のロックを解放し、カレントスレッドを停止します。 ConditionVariable#signalまたは、 ConditionVariable#broadcastで送られたシグナルを 受け取ると、mutexのロックを取得し、実行状態となります。

継承したメソッド

== === =~ __id__ __send__ _dump class clone dclone display enum_for eql? equal? extend freeze frozen? hash initialize initialize_copy inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? marshal_dump marshal_load method method_missing methods nil? pretty_inspect pretty_print pretty_print_cycle pretty_print_inspect pretty_print_instance_variables private_methods protected_methods public_methods remove_instance_variable respond_to? singleton_method_added singleton_method_removed singleton_method_undefined singleton_methods taint tainted? tap to_a to_ary to_hash to_int to_io to_proc to_regexp to_s to_str to_yaml to_yaml_properties to_yaml_style untaint