红宝石简单的竞争条件问题

时间:2010-11-16 12:44:29

标签: ruby multithreading race-condition

我遇到了一个竞争条件的例子:

def inc(n)
  n + 1
end

sum = 0

threads = (1..10).map do
  Thread.new do
    10_000.times do
      sum = inc(sum)
    end
  end
end

threads.each(&:join)
p sum

线程以pararell运行,并且有可能当一个线程读取sum的值时,另一个线程完成递增它,但前者即将用旧值完成自己的递增,因此sum将不会改变。

但我想知道,为什么当我将'sum = inc(sum)'行替换为'sum + = 1'时,输出似乎总是正确的。

为什么?

是否因为调用方法的开销与仅执行变量赋值相比是如此巨大,因此某些线程“失去同步”导致输出不正确?

我假设,即使有一个直的+ + 1,我仍然能够观察到竞争条件,但前提是我已经做了更长的求和循环等等?

1 个答案:

答案 0 :(得分:3)

  

是否因为调用方法的开销与仅执行变量赋值相比是如此巨大,因此某些线程“失去同步”导致输出不正确?

是。要验证它,只需增加计数器并运行多个测试。我把它增加到100_000.times,结果如下:

$ seq 5 | xargs -L 1 ruby a.rb 100000
451167
472581
464413
442191
454204

嗯,它看起来不太好,是吗?

所以,是的,Ruby中的增量不是原子的(我怀疑它有很多语言)。但是有辅助类来实现这样的行为;例如,this one