Performing writes/reads on class variables in Ruby is not thread safe. Performing writes/reads on instance variables appears to be thread safe. That said, is it thread safe to perform write/reads on instance variables of a class or metaclass object?
What are the differences between these three (contrived) examples in terms of thread safety?
EXAMPLE 1: MUTUAL EXCLUSION
class BestUser # (singleton class)
@@instance_lock = Mutex.new
# Memoize instance
def self.instance
@@instance_lock.synchronize do
@@instance ||= best
end
end
end
EXAMPLE 2: INSTANCE VARIABLE STORAGE
class BestUser # (singleton class)
# Memoize instance
def self.instance
@instance ||= best
end
end
EXAMPLE 3: INSTANCE VARIABLE STORAGE ON METACLASS
class BestUser # (singleton class)
# Memoize instance
class << self
def instance
@instance ||= best
end
end
end
Instance variables are not thread safe (and class variables are even less thread safe)
Example 2 and 3, both with instance variables, are equivalent, and they are NOT thread safe, like @VincentXie stated. However, here is a better example to demonstrate why they are not:
class Foo
def self.bar(message)
@bar ||= message
end
end
t1 = Thread.new do
puts "bar is #{Foo.bar('thread1')}"
end
t2 = Thread.new do
puts "bar is #{Foo.bar('thread2')}"
end
sleep 2
t1.join
t2.join
=> bar is thread1
=> bar is thread1
Because the instance variable is shared amongst all of the threads, like @VincentXie stated in his comment.
PS: Instance variables are sometimes referred to as "class instance variables", depending on the context in which they are used:
When self is a class, they are instance variables of classes(class instance variables). When self is a object, they are instance variables of objects(instance variables). - WindorC's answer to a question about this