我有以下代码(from a Ruby tutorial):
require 'thread'
count1 = count2 = 0
difference = 0
counter = Thread.new do
loop do
count1 += 1
count2 += 1
end
end
spy = Thread.new do
loop do
difference += (count1 - count2).abs
end
end
sleep 1
puts "count1 : #{count1}"
puts "count2 : #{count2}"
puts "difference : #{difference}"
counter.join(2)
spy.join(2)
puts "count1 : #{count1}"
puts "count2 : #{count2}"
puts "difference : #{difference}"
这是使用Mutex.synchronize
的一个例子。在我的计算机上,结果与教程完全不同。调用join
后,计数有时相等:
count1 : 5321211
count2 : 6812638
difference : 0
count1 : 27307724
count2 : 27307724
difference : 0
有时不是:
count1 : 4456390
count2 : 5981589
difference : 0
count1 : 25887977
count2 : 28204117
difference : 0
我不明白差异是如何仍然0
,即使计数显示的数字非常不同。
add
操作可能如下所示:
val = fetch_current(count1)
add 1 to val
store val back into count1
和count2
类似的东西。 Ruby可以在线程之间切换执行,因此它可能无法完成对变量的写入,但是当CPU返回到线程时,它应该从它被中断的行继续,对吧?
还有一个线程正在写入变量。如何在loop do
块中count2 += 1
执行更多次?
答案 0 :(得分:3)
执行
puts "count1 : #{count1}"
需要一些时间(尽管可能很短)。它不是在一个实例中完成的。因此,连续两行并不神秘:
puts "count1 : #{count1}"
puts "count2 : #{count2}"
显示不同的计数。简单地说,counter
线程经历了一些循环周期,并在执行第一个puts
时增加了计数。
同样,
时difference += (count1 - count2).abs
计算,在引用count1
之前引用count2
时,计数原则上可以递增。但是在该时间跨度内没有执行命令,我猜测引用count1
所花费的时间比counter
线程通过另一个循环所花费的时间要短得多。请注意,前者中的操作是后者中所做操作的适当子集。如果差异足够大,这意味着counter
线程在-
方法的参数调用期间没有经历循环周期,那么将出现count1
和count2
同样的价值。
如果您在引用count1
之后但在引用count2
之前进行了一些昂贵的计算,则会出现预测:{/ 1}}将显示:
difference
答案 1 :(得分:0)
这是答案。我认为你假设线程在join(2)
返回后停止执行。
事实并非如此!即使join(2)
将执行(暂时)返回到主线程,线程仍继续运行。
如果您将代码更改为此,您将看到会发生什么:
...
counter.join(2)
spy.join(2)
counter.kill
spy.kill
puts "count1 : #{count1}"
puts "count2 : #{count2}"
puts "difference : #{difference}"
这似乎在ruby 1.8中有点不同,其中线程在主线程执行时似乎没有机会运行。
本教程可能是为ruby 1.8编写的,但从那时起,线程模型已在1.9中进行了更改。
实际上它在1.8中工作是纯粹的“运气”,因为当join(2)
在1.8和1.9中都没有返回时,线程没有完成执行。