スレッドごとに固有のデータを管理したい。
Rubyのスレッドは、スレッド固有のデータを持つことができます。Thread.currentで現在実行中のスレッドが取得できるので、これと組み合わせてJavaのThreadLocalのように使うことができます。
ts = [] 3.times{|i| ts << Thread.fork(i) {|i| # # スレッド固有のデータを使う。 # Thread.current[:count]はスレッドごとに確保されるので、 # 生成した3つのスレッドで値が共有されることはない。 # Thread.current[:count] = 0 10.times {|j| Thread.current[:count] += 1 puts i.to_s << ":" << Thread.current[:count].to_s sleep rand * 0.1 } } } ts.each {|t| t.join }
実行結果です。
0:1 1:1 2:1 2:2 0:2 2:3 1:2 0:3 2:4 0:4 0:5 1:3 1:4 0:6 2:5 2:6 1:5 0:7 2:7 1:6 0:8 0:9 1:7 0:10 1:8 2:8 1:9 2:9 1:10 2:10
ただし、ThreadLocalと違って、他のスレッドからも領域にアクセス可能です。なので別スレッドからも使う場合は排他制御が必要です。
# スレッド / Thread.current[:count]の値をインクリメント。 t = Thread.fork { Thread.current[:count] = 0 100.times {|j| count = Thread.current[:count] # この辺で運悪くスレッドが切り替わると、 # hread.current[:count]が1つづつインクリメントされない場合が起こる。 count += 1 Thread.current[:count] = count puts "thread:" << Thread.current[:count].to_s } } # メインスレッドでもt[:count]を更新 100.times {|j| count = t[:count] count += 1 t[:count] = count puts "main:" << t[:count].to_s } t.join
実行結果です。★のあたりでメインスレッドで行われたはずの更新がすっ飛ばされています。
... thread:10 thread:11 thread:12 main:13 main:14 main:15 main:16 main:17 main:18 main:19 main:20 main:21 main:22 main:23 main:24 main:25 main:26 main:27 main:28 main:29 main:30 main:31 main:32 main:33 main:34 main:35 thread:13 ★ thread:14 thread:15 thread:16 thread:17 thread:18 thread:19 thread:20 ...