2010-11-16 100 views
5

我碰到的一個競爭條件的例子:紅寶石簡單的競爭狀態的問題

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 = inc(sum)'換成'sum + = 1'時,輸出看起來總是正確的。

這是爲什麼?

是不是因爲調用方法的開銷比做變量賦值這麼大,因此一些線程'不同步'導致輸出不正確?

我認爲,即使是直線和+ = 1,我仍然能夠觀察到比賽情況,但只有當我進行了更長的求和循環等時才能觀察到比賽情況。

回答

3

是因爲調用一個方法的開銷比只做一個變量賦值和因此一些線程'不同步'導致輸出不正確嗎?

是。要驗證它,只需增加計數器並運行多個測試。我把它提高到100_000.times和這裏的結果:

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

嗯,這似乎不是很好,不是嗎?

所以,是的,增量在Ruby中不是原子的(我懷疑它有很多語言)。但是有助手類來實現這種行爲;例如,this one