MRezk
MRezk

Reputation: 61

Aren't ruby Queues thread safe why is the queue not synchronizing?

I am trying to create many threads and return the result in a data structure and I read that Queue is thread-safe, but when I run the code it doesn't produce the expected result.

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

The code prints: (always a little different)

4
4
4
4
10
10
10
10
10
10

I was expecting the numbers 1 through 10.

I have tried to synchronize it manually to no avail:

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

What am I missing?

Upvotes: 3

Views: 1088

Answers (1)

Stefan
Stefan

Reputation: 114178

Queue is thread-safe but your code is not. Just like variable queue, variable i is shared across your threads, so the threads refer to the same variable while it is being changed in the loop.

To fix it, you can pass the variable to Thread.new, which turns it into a thread-local variable:

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

The i within the block shadows the outer i, because they have the same name. You can use another name (e.g. |thread_i|) if you need both.

Output:

3
2
10
4
5
6
7
8
9
1

Upvotes: 5

Related Questions