読者です 読者をやめる 読者になる 読者になる

Rubyでスレッドセーフでないことを簡単に確認したい

RubyのスレッドにはGiant VM lock (GVL) (Global Interpreter lock) が実装されており、同時に実行される ネイティブスレッドは常にひとつです。なので、スレッドセーフでないプログラムを実行しても、排他制御が効いているように見えます。
例えば次のコードを実行すると

variable = 0
flag = true

threads = 5.times.map do 
  Thread.new do
    if flag
      variable += 1
      flag = false
    end
  end
end

threads.each(&:join)

puts variable

1が出力されます。何度でも。
スレッドセーフでないコードなのに結果が毎回1になるのはGVLのためです。
ここでスレッドセーフでない振る舞いをあらわに知りたいときは次のようにすればOKです。

variable = 0
flag = true

threads = 5.times.map do 
  Thread.new do
    if flag
      puts "not thread safe"
      variable += 1
      flag = false
    end
  end
end

threads.each(&:join)

puts variable

標準出力を組み込むことで、実行結果は実行のたびに異なります。
これは、RubyのスレッドはIO時にはGVLを開放するためです。

ちなみにRubyのバージョンは

ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]

でした。

参考:http://docs.ruby-lang.org/ja/2.1.0/class/Thread.html