Ruby 共享实例变量是否需要在多个线程中执行原子操作?(螺纹安全)

Ruby 共享实例变量是否需要在多个线程中执行原子操作?(螺纹安全),ruby,concurrency,atomic,Ruby,Concurrency,Atomic,下面的代码是线程安全的吗 @total_count = 0 t = [] 100.times do t << Thread.new do 100.times do @total_count += 2 end end end t.map(&:join) p @total_count @total\u count=0 t=[] 100.5倍 tNo,代码不是线程安全的。由于GIL/GVL(全局解释器锁/全局VM锁)的影响,它只在某些Ruby

下面的代码是线程安全的吗

@total_count = 0
t = []
100.times do
  t << Thread.new do
    100.times do
       @total_count += 2
    end
  end
end
t.map(&:join)
p @total_count
@total\u count=0
t=[]
100.5倍

tNo,代码不是线程安全的。由于GIL/GVL(全局解释器锁/全局VM锁)的影响,它只在某些Ruby解释器(例如Ruby 2.0(MRI/KRI))中出现。在这种情况下,它可能会产生您期望的结果(
20000
)——但这种方法通常不能保证安全性

在JRuby解释器中运行代码(该解释器没有GIL并且以真正的并行方式运行线程)会在不同的运行中给出不同的结果,例如:

jruby-1.7.6 :011 > p @total_count
16174
 => 16174 
@total\u count+=2
扩展为
@total\u count=@total\u count+2
,这意味着线程可以在RHS读取和LHS写入之间交错。这意味着总数可能(也将经常)比预期总数少(但在本例中,不会多)。通过使用
互斥锁
,可以使代码成为线程安全的:

@mutex = Mutex.new
@total_count = 0
t = []
100.times do
  t << Thread.new do
    100.times do
      @mutex.synchronize do
        @total_count += 2
      end
    end
  end
end
t.map(&:join)
p @total_count
我意识到这与你的问题不同(我理解这是关于
+=
是否是原子的),但即使在Ruby 2.0(MRI/KRI)中,也可以通过扩展赋值和插入一个小睡眠来证明这一原理:

@total_count = 0
t = []
100.times do
  t << Thread.new do
    100.times do
      total_count = @total_count
      sleep 0.0000001
      @total_count = total_count + 2
    end
  end
end
t.map(&:join)
p @total_count
但是,使用
互斥锁

@mutex = Mutex.new
@total_count = 0
t = []
100.times do
  t << Thread.new do
    100.times do
      @mutex.synchronize do
        total_count = @total_count
        sleep 0.0000001
        @total_count = total_count + 2
      end
    end
  end
end
t.map(&:join)
p @total_count
2.0.0p247 :013 >     p @total_count
512
 => 512 
@mutex = Mutex.new
@total_count = 0
t = []
100.times do
  t << Thread.new do
    100.times do
      @mutex.synchronize do
        total_count = @total_count
        sleep 0.0000001
        @total_count = total_count + 2
      end
    end
  end
end
t.map(&:join)
p @total_count
2.0.0p247 :224 > p @total_count
20000
 => 20000