From: Shin-ichiro Hara Date: 1999-06-17T13:25:05+09:00 Subject: [ruby-list:15031] Re: ConditionVariable (cv3.rb) 原です。 In message "[ruby-list:15030] ConditionVariable (cv3.rb)" on 99/06/17, Shin-ichiro Hara writes: |test1.rb を改造した test-cv.rb(後掲)で、バッファサイズ3のパ |イプに、送り手4スレッド受け手3スレッドでオブジェクトを通すも |のです。停止するのは全ての受け手スレッドが 1000 個のオブジェク |トを受け取った時とします。 一応 test-cv.rb です。無いよりましという程度で、必ずしもポイント をついたいいテストプログラムというわけではありません。 幾つかパラメータをコマンドライン・パラメータに取るので、いろいろ やってみると面白いですが、数字によって結構(数論的な?)動きがあ ったりして、実は簡単に結論が出せません。cv3.rb はパラメータによ らず比較的安定しているのは確かですが。もうちょっとちゃんとしたテ ストプログラムが無いとこれ以上の効率や適正性の追求は難しそうです。 (バッファサイズ10送り手12受け手3で100回す例) $ ruby test-cv.rb max10 s12 r3 100 cv3.rb -------------^ test-cv.rb #!/usr/local/bin/ruby Thread.abort_on_exception = true $sender_num = 4 $receiver_num = 3 $rtimes = 1000 $max = 3 $debug = 0 while para = ARGV.shift case para when /^n$/ $no_signal_mutex = true when /^p$/ $pass = true when /^d(\d)?$/ $debug = ($1||1).to_i when /^\d+$/ $rtimes = $&.to_i when /^max(\d+)$/ $max = $1.to_i when /^r(\d+)$/ $receiver_num = $1.to_i when /^s(\d+)$/ $sender_num = $1.to_i else $o = para end end class Thread Num = [0] Obj2num = {Thread.current => 0} def Thread.start0 Num[0] = Num[0]+1 t = Thread.start { Thread.stop yield } Obj2num[t] = Num[0] t end def num Obj2num[self] end def Thread.num Obj2num[Thread.current] end alias to_s0 to_s def inspect; "#{Obj2num[self]}"; end def to_s; "#{Obj2num[self]}"; end end case $o when /cv(\d+)/ require $o $ver = $1.to_i $full = ConditionVariable.new $mutex = Mutex.new if $ver > 2 $signal_param = $mutex unless $no_signal_mutex end $wait_param = $mutex $empty = ConditionVariable.new when /^monitor/ require $o $mutex = Monitor.new $full = $mutex.new_cond $empty = $mutex.new_cond when /^mutex/ require $o $mutex = Mutex.new $full = ConditionVariable.new($mutex) $empty = ConditionVariable.new($mutex) else raise "can't get option: #$o" end print "TEST CONDITION VARIABLE <<< #{$o.upcase} >>>\n" printf("Sender:%d, Receiver:%d (each receives %d times), Buffer:#$max\n", $sender_num, $receiver_num, $rtimes) $queue = [] $rwaste = 0 $rwaste1 = 0 $swaste = 0 $swaste1 = 0 $snds = [] $rcvs = [] $snds_times = {} $rcvs_times = {} $sender_num.times do $snds.push Thread.start0 { n = 0 $snds_times[Thread.current] = 0 loop do $mutex.synchronize { k = 0 while $queue.size >= $max k += 1 if $wait_param $full.wait($wait_param) else $full.wait end $swaste += 1 if k > 1 end $swaste1 += 1 if k > 1 $queue.push [n, Thread.num] if $queue.size >= 1 # == true if $signal_param $empty.signal($signal_param) else $empty.signal end end } n += 1 $snds_times[Thread.current] = n Thread.pass if $pass end } end $receiver_num.times do $rcvs.push Thread.start0 { n = 0 $rcvs_times[Thread.current] = 0 $rtimes.times do $mutex.synchronize { k = 0 while $queue.size <= 0 k += 1 if $wait_param $empty.wait($wait_param) else $empty.wait end $rwaste += 1 if k > 1 end $rwaste1 += 1 if k > 1 v = $queue.shift if $queue.size < $max if $signal_param $full.signal($signal_param) else $full.signal end end printf("get %s (#%s->#%s)\n", v[0], v[1], Thread.num) if $debug > 0 } n += 1 $rcvs_times[Thread.current] = n Thread.pass if $pass end } end # START Thread.critical = true Thread::Obj2num.each do |t, n| t.wakeup if n > 0 end Thread.critical = false $rcvs.each do |t| VERSION.to_f >= 1.3 ? t.join : Thread.join(t) end $snds.each do |t| Thread.kill(t) end printf("Idling1: send =%2d, receive =%2d\n", $swaste1, $rwaste1) printf("Idling2: send =%2d, receive =%2d\n", $swaste, $rwaste) $snds.each do |t| printf("#%s sends %d times\n", t, $snds_times[t]) end -------------$ test-cv.rb 以外と長かった。(^^;