rubyyarv

Are YARV Arrays' push/pop methods thread-safe?


Suppose I have a pair of (producer, consumer) YARV threads (Tp,Tc) sharing an Array q - Tp pushes to q, and Tc pops from it. If the order in which the pushes and pops get executed is unimportant, does the code work without any synchronization mechanism?


Solution

  • Accessing arrays is thread-safe in MRI/YARV (and only there) most of the time due to its global interpreter lock (GIL), thus mostly by accident.

    You still would have to make sure that you are only performing a single operation each time and avoid read/write constructs. In other Ruby implementations like Rubinius or JRuby, Arrays are explicitly not thread safe.

    With that being said, Ruby ships with a different primitive for inter-thread communication, which co-incidentaly is about the only class in MRI/VARV which is explicitly thread-safe: the Queue. It supports pushing and poping objects in a thread-safe way.

    Take this example from Ruby's documentation:

    queue = Queue.new
    
    producer = Thread.new do
      5.times do |i|
         sleep rand(i) # simulate expense
         queue << i
         puts "#{i} produced"
      end
    end
    
    consumer = Thread.new do
      5.times do |i|
         value = queue.pop
         sleep rand(i/2) # simulate expense
         puts "consumed #{value}"
      end
    end
    

    There also exists a well-maintained project called concurrent-ruby which offers a lot of powerful primitives for concurrent programming across threads.