ConditionVariable

執筆者募集 *1 *2

スレッドの同期機構の一つである状態変数を実現するクラス。 ConditionVariable オブジェクトはスレッドが待ち合わせを行う条 件をオブジェクト化したものです。

mutex = Mutex.new
cv = ConditionVariable.new

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

*3

あるスレッドで上のように条件が満たされるまで wait メソッドで スレッドを止めて、他のスレッドで

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

として、signal メソッドで wait を実行しているスレッドに対し て条件が成立したことを通知するのが典型的な使用例です。

*4

以下は 「Pthread プログラミング」にあった ConditionVariable の例をRuby で書いてみた。なぜか最後にデッドロックする。 *5

require 'thread'

count_lock = Mutex.new
count_hit_threshold = ConditionVariable.new
count = 0
COUNT_THRESHOLD = 10

inc_count = proc {
  loop {
    count_lock.synchronize {
        count += 1
        p [Thread.current, count]
        if count >= COUNT_THRESHOLD
          count_hit_threshold.signal
          Thread.exit
        end
    }
  }
}

ths = []
ths << Thread.new(&inc_count)
ths << Thread.new(&inc_count)
ths << Thread.new {
  loop {
    count_lock.synchronize {
        if count > 0
          count -= 1
        end
        p [Thread.current, count]
    }
  }
}
ths << Thread.new {
  cond_lock.synchronize {
    while (count < COUNT_THRESHOLD)
      count_hit_threshold.wait(count_lock)
      p [Thread.current, count, 'wait']
    end
  }
}

ths.each {|t|
  t.join
}

スーパークラス:

クラスメソッド:

ConditionVariable.new

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

メソッド:

broadcast

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

実行待ちしていたスレッドの配列を返します。

signal

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

状態を待っているスレッドがあった場合は、そのスレッドを返します。 そうでなければ nil を返します。

wait(mutex)

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

self を返します。


*1あらい 2001-10-07: まだ理解できない、理解できないから書けない。 ruby-list:6735[外部]
*2あらい 2002-01-03: 全体的に記述が怪しいのですが間違ってて も表に出さないと突っ込まれもしないのでコメントをはずしました。 このページ全文信じないように
*3m は mutex か
*4ruby-list:14445[外部] に例があります
*5waitの後に、mutexの解放を行っていませんでした。修正しておきます