Ruby的队列不是线程安全的,为什么队列没有同步?

3

我尝试创建许多线程并将结果返回到一个数据结构中,我读到 Queue 是线程安全的,但是当我运行代码时它没有产生预期的结果。

require 'thread'

class ThreadsTest
  queue = Queue.new
  threads = []
  for i in 1..10
    threads << Thread.new do 
      queue << i
    end
  end

  threads.each { |t| t.join }

  for i in 1..10
    puts queue.pop()
  end
end

代码输出结果为:(总是稍有不同)
4
4
4
4
10
10
10
10
10
10

我期望看到1到10的数字。

我尝试手动同步,但没有成功:

  mutex = Mutex.new
  for i in 1..10
    threads << Thread.new do 
      mutex.synchronize do
        queue << i
      end
    end
  end

我错过了什么?


顺便说一句,把这样的代码直接放在“class”块中很奇怪。你应该将其包装在一个方法中。 - Stefan
1个回答

5

Queue是线程安全的,但是你的代码不是。就像变量queue一样,变量i在你的线程之间是共享的,因此线程在循环中修改它时引用的是同一个变量。

为了解决这个问题,你可以将变量传递给Thread.new,这将把它转换为线程本地变量:

threads << Thread.new(i) do |i|
  queue << i
end

在代码块中,i 会覆盖外部的 i,因为它们具有相同的名称。如果您需要同时使用两个变量,请使用另一个名称(例如 |thread_i|)。

输出:

3
2
10
4
5
6
7
8
9
1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接