Threadの同期。

カフェでラスクを食べた。ラスクを前歯でシャクシャクと食べていると、リスになったような気分が味わえるのが好きだ。
昨日に引き続きThread。Threadの同期をやってみる。ほぼ写経。

#!/usr/bin/env ruby

class Counter
  attr_reader:count

  def initialize
    @count = 0
  end

  def tick
    @count += 1
  end

end

counter = Counter.new

thread1 = Thread.new { 100000.times { counter.tick }}
thread2 = Thread.new { 100000.times { counter.tick }}

thread1.join
thread2.join

p counter.count

結果。

131013

もういっちょ。

142144

使えねぇ。
こうなるのは

@count += 1

1つめのスレッドが@count = 1の状態で実行したとして、2つめのスレッドは@count = 2に対して+1して欲しいけど、同時に実行され、@count = 1の状態で実行されてしまうことがあるため。
これを防ぐためには

@count += 1

を複数のスレッドで同時に実行できないようにする必要がある。

#!/usr/bin/env ruby

require 'monitor'

# Monitorクラスを継承
class Counter < Monitor
  attr_reader:count

  def initialize
    @count = 0
    # 忘れたらdeadlockが発生したので忘れずに
    super
  end

  def tick
    # 複数のスレッドで同時に処理を行わないようにする
    synchronize do
      @count += 1
    end
  end

end

counter = Counter.new

thread1 = Thread.new { 100000.times { counter.tick }}
thread2 = Thread.new { 100000.times { counter.tick }}

thread1.join
thread2.join

p counter.count

結果。

 200000

おけ。


プログラミングRuby 第2版 言語編

プログラミングRuby 第2版 言語編