例として12次元ベクトルを前半、後半に分けて、前半の内積、後半の内積を2つのTheadを使って求める。2つの内積の和が求めたい内積の値となる。
前半の内積、後半の内積を計算するProc(クロージャー)を作ってQueueに放り込むコードは次の通り。
前半の内積、後半の内積を変数sumに蓄積したいが、この計算はThread安全に行いたいのでクリティカルセクションとしたい。
クリティカルセクションにしたいクロージャーは、Mutexオブジェクトのsynchromizeメソッドの引数に与えれば作ることができる。
# 内積の計算を2Threadで実行。
ary0 = [0.4, 0.2, 0.3, 0.5, 0.2, 0.4, 0.5, 0.1, 0.2, 0.4, 0.5, 0.9]
ary1 = [0.1, 0.2, 0.2, 0.2, 0.3, 0.4, 0.4, 0.4, 0.5, 0.5, 0.5, 0.9]
sum = 0
lock = Mutex.new
q = Queue.new
[{:from => 0, :to => ary0.size/2},
{:from => ary0.size/2+1, :to => ary0.size-1}].each {|e|
q.push proc {
t = 0
e[:from].upto(e[:to]) {|i|
t = t + ary0[i] * ary1[i]
}
lock.synchronize { sum = sum + t }
}
}
Queueからクロージャーを取り出して実行するThreadを2個作る。作った時に返るThreadハンドルは配列に格納しておく。
これで、main Threadとは別のThreadが作られ走り始めるが、作られたThreadが終わるのをmain Threadで待ち構えるためにThreadハンドルが使われる。
th = []
0.upto(1) {|i|
until q.empty?
th << Thread.start(q.pop) {|e|
e.call
}
end
}
# 0.upto(1) {|i|
# th << Thread.new {
# until q.empty?
# q.pop.call
# end
# }
2つのThreadが終わるをmain Threadで待って内積の値を表示する。
th.each {|t| t.join}
puts sum
検算のためにThreadを使わずに内積の計算をして、Threadを使った場合の結果と比較してみる。両者の値はコード末尾の2つの値で一致する。
# 2Threadで実行して得た結果と、main Threadで計算して得た結果を比較
checksum = 0
ary0.each_with_index {|e, i|
checksum = checksum + ary0[i] * ary1[i]
}
puts checksum
__END__
2.0600000000000005
2.0600000000000005