2010-11-16 11 views
5

me encontré con este ejemplo de una condición de carrera:rubí condición de carrera simple pregunta

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 

Hilos correr en pararell y existe la posibilidad de que mientras un hilo lee el valor de suma, otra completa incrementarlo, pero el primero está a punto de terminar su propio incremento con el valor anterior, y como resultado la suma no cambiará.

Pero me preguntaba, ¿por qué cuando reemplazo la línea 'suma = inc (suma)' por 'suma + = 1', la salida parece ser siempre correcta.

¿Por qué es eso?

¿Es porque la sobrecarga de llamar a un método es tan grande en comparación con solo hacer una asignación de variable y, por lo tanto, algunos subprocesos 'no están sincronizados' y la salida es incorrecta?

Supongo que, incluso con una suma directa + = 1, aún podría observar una condición de carrera, pero solo si hubiera estado haciendo un ciclo de suma mucho más largo, etc.

Respuesta

3

¿Es porque la sobrecarga de llamar a un método es tan grande en comparación con solo hacer una asignación de variable y por lo tanto algunos subprocesos 'salen de sincronización' causando que la salida sea incorrecta?

Sí. Para verificarlo, simplemente aumente su contador y realice varias pruebas. He aumentado a 100_000.times y aquí están los resultados:

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

Bueno, no parece tan bonita, ¿verdad?

Por lo tanto, sí, el incremento no es atómico en Ruby (y dudo que haya muchos idiomas). Pero hay clases de ayuda para implementar dicho comportamiento; por ejemplo, this one.

Cuestiones relacionadas