首页 > 解决方案 > 用 Ruby 解释这种竞争条件

问题描述

四个线程每个循环 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,竞争条件是如何发生的?

标签: rubymultithreading

解决方案


当时只执行一个线程并不意味着一个线程总是在有用的行停止,例如在下一个线程获得其执行时间之前在块的末尾。

在您的示例中,一个线程可能会读取和评估list.empty?,然后必须等待另一个线程。另一个线程也读取和评估list.empty?并获得与第一个线程相同的结果。之后,两个线程将执行相同的if条件分支,因为它们看到了相同的状态。


推荐阅读