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]
でした。