Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the << operation on an array in Ruby not atomic?

In Ruby, this code is not threadsafe if array is modified by many threads:

array = []
array << :foo # many threads can run this code

Why is the << operation not thread safe?

like image 445
Sławosz Avatar asked Jul 20 '13 18:07

Sławosz


People also ask

What does << mean in Ruby Array?

In ruby '<<' operator is basically used for: Appending a value in the array (at last position) [2, 4, 6] << 8 It will give [2, 4, 6, 8] It also used for some active record operations in ruby.

Are Ruby arrays thread safe?

In standard Ruby implementations, an Array is not thread-safe.


3 Answers

Actually using MRI (Matz's Ruby implementation) the GIL (Global Interpreter Lock) makes any pure C-function atomic.

Since Array#<< is implemented as pure C-code in MRI, this operation will be atomic. But note this only applies to MRI. On JRuby this is not the case.

To completely understand what is going on I suggest you read these two articles, which explains everything very well:

Nobody Understands the GIL
Nobody Understands the GIL - part 2

like image 79
Casper Avatar answered Nov 03 '22 20:11

Casper


If you have multiple threads accessing the same array, use Ruby's built-in Queue class. It nicely handles producers and consumers.

This is the example from the documentation:

require 'thread'

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

consumer.join
like image 21
the Tin Man Avatar answered Nov 03 '22 18:11

the Tin Man


array is your program variable when you apply an operation like << to it. It happens in three-steps:

  • The variable is first copied into a CPU register.
  • The CPU performs computations.
  • The CPU writes back the result to variable memory.

So this high-level single-operation is performed in three steps. In between these steps, due to thread-context switching, other thread may read the same (old) value of the variable. That's why it's not an atomic operation.

like image 23
Grijesh Chauhan Avatar answered Nov 03 '22 20:11

Grijesh Chauhan