四个线程分别循环1000万次。在每个循环中,如果列表为空,他们会推送一个数字,否则会从列表中弹出一个数字。
list = []
threads = []
4.times do |i|
threads << Thread.new do
1e7.to_i.times do |i|
if list.empty?
list << i
else
list.pop
end
end
end
end
threads.each(&:join)
p list
由于循环执行偶数次,所以我希望所有线程执行完后,列表为空。
但是,有时列表中包含数字9999999。
由于GIL,我认为MRI Ruby中的Array是线程安全的。
尽管有GIL,比赛条件如何发生?
答案 0 :(得分:2)
一次仅执行一个线程并不意味着一个线程总是在有用的行处停止,例如在下一个线程获得执行时间之前在一个块的末尾。
在您的示例中,一个线程有可能读取并评估list.empty?
,然后必须等待另一个线程。另一个线程也读取并求值list.empty?
,并获得与第一个线程相同的结果。之后,两个线程将执行if
条件的相同分支,因为它们看到的状态相同。