スレッドの同期機構の一つである状態変数を実現するクラスです。
以下も ConditionVariable を理解するのに参考になります。
<URL:http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html#UF>[外部]
あるスレッド 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
ConditionVariable.new
状態変数を生成して返します。
broadcast
状態変数を待っているスレッドをすべて再開します。再開された スレッドは ConditionVariable#wait で指定した mutex のロックを試みます。
実行待ちしていたスレッドの配列を返します。
signal
状態変数を待っているスレッドを1つ再開します。再開された スレッドは ConditionVariable#wait で指定した mutex のロックを試みます。
状態を待っているスレッドがあった場合は、そのスレッドを返します。
そうでなければ nil
を返します。
wait(mutex)
mutex のロックを開放し、カレントスレッドを停止します。 ConditionVariable#signalまたは、 ConditionVariable#broadcastで送られたシグナルを 受け取ると、mutexのロックを取得し、実行状態となります。
self
を返します。