我正在试验多线程示例。我尝试使用以下代码产生竞争条件。但我总是得到相同的(正确的)输出。类 Counter attr_reader:...
我正在试验多线程示例。我尝试使用以下代码产生竞争条件。但我总是得到相同(正确)的输出。
class Counter
attr_reader :count
def initialize
@count = 0
end
def increment
@count += 1
end
def decrement
@count -= 1
end
end
c = Counter.new
t1 = Thread.start { 100_0000.times { c.increment } }
t2 = Thread.start { 100_0000.times { c.increment } }
t1.join
t2.join
p c.count #200_0000
我能够使用每个线程中更少的迭代次数来观察 Java 中的竞争条件。是不是因为我运行的次数不够多而导致竞争条件产生,还是 +
-
中的线程是安全的?我使用的是 ruby 2.0.0p247
这是因为 MRI Ruby 线程由于 GIL(参见 此处 )而并非真正并行,在 CPU 级别它们一次只执行一个。
线程中的每个命令一次执行一个,因此 @count
每个线程始终正确更新。
可以通过添加另一个变量来模拟竞争条件,例如:
class Counter
attr_accessor :count, :tmp
def initialize
@count = 0
@tmp = 0
end
def increment
@count += 1
end
end
c = Counter.new
t1 = Thread.start { 1000000.times { c.increment; c.tmp += 1 if c.count.even?; } }
t2 = Thread.start { 1000000.times { c.increment; c.tmp += 1 if c.count.even?; } }
t1.join
t2.join
p c.count #200_0000
p c.tmp # not 100_000, different every time
这里 给出了一个很好的竞争条件示例 ,为了完整性,下面复制了
class Sheep
def initialize
@shorn = false
end
def shorn?
@shorn
end
def shear!
puts "shearing..."
@shorn = true
end
end
sheep = Sheep.new
5.times.map do
Thread.new do
unless sheep.shorn?
sheep.shear!
end
end
end.each(&:join)
这是我在 MRI 2.0 上多次运行后看到的结果。
$ ruby check_then_set.rb => 剪切...
$ ruby check_then_set.rb => 剪切... 剪切...
$ ruby check_then_set.rb => 剪切... 剪切...
有时同一只羊会被剪两次毛!