原です。
In message "[ruby-list:14847] Re: ConditionVariable (again)"
on 99/06/07, Shugo Maeda <shugo / netlab.co.jp> writes:
|
|前田です。
|> 結局、私のあの単純な CV のコード(cv2.rb)、あれはあれでちゃん
|> と動くんですよね。
|
|競合する(条件を偽にしようとする)スレッドにロックを横取りされる可
|能性はあります。
そうですね。だから、ユーザーの条件変数の一般的利用法としては、
mutex.synchronize {
...
if ある条件
cond_var.wait(mutex)
end
...
}
ではなくて、スレッドにロックを横取りされることを前提に
mutex.synchronize {
...
while ある条件
cond_var.wait(mutex)
end
...
}
と書くべきなんですね。せきさんのプログラムでは前者で十分だけど。
|ただ、私のコードでも、競合するスレッドで、
|
|1000.times do
| break if m.try_lock
| Thread.pass
|end
|
|などとされるとだめですね。
monitor.rb では、signal のスレッドから1周する間に競合するス
レッドの幾つかを止めて回るので、2周目、sinal のスレッドから
wait のスレッドに移動する間に邪魔される確率が減る、またそこ
でロックを横取りされても優先的に取り戻すので同じスレッドに2
度邪魔されることは殆んどない(1度はあるかもしれないが)、と
いう様なメカニズムでしょうか。
実験:
-----^ test1.rb
#!/usr/bin/ruby
Thread.abort_on_exception = true
require "monitor"
$mutex = Monitor.new
$full = $mutex.new_cond
$empty = $mutex.new_cond
$queue = []
$max = 1
$waste = 0
$waste1 = 0
3.times do
Thread.new {
n = 0
loop do
$mutex.synchronize {
k = 0
while $queue.size >= $max
k += 1
$full.wait
$waste += 1 if k > 1
end
$waste1 += 1 if k > 1
$queue.push n
$empty.signal if $queue.size >= 1
}
n += 1
end
}
end
1000.times do
$mutex.synchronize {
while $queue.size <= 0
$empty.wait
end
v = $queue.shift
$full.signal if $queue.size < $max
}
end
print $waste, ", ", $waste1, "\n"
-----$ test1.rb
これを実行すると $waste == $waste1 で一桁ぐらいです。
これを cv2.rb の ConditionVariable で書くと $waste1 が
数倍、$waste は数十倍。かなり違うものですね。