ruby - 线程安全 : Class Variables in Ruby

标签 ruby multithreading thread-safety metaprogramming ruby-1.9.2

在 Ruby 中对类变量执行写入/读取操作不是线程安全的。对实例变量执行写入/读取似乎是线程安全的。也就是说,对类或元类对象的实例变量执行写入/读取是否线程安全?

这三个(人为的)示例在线程安全方面有何区别?

示例 1:相互排斥

class BestUser # (singleton class)
  @@instance_lock = Mutex.new

  # Memoize instance
  def self.instance
    @@instance_lock.synchronize do
      @@instance ||= best
    end
  end
end

示例 2:实例变量存储

class BestUser # (singleton class)
  # Memoize instance
  def self.instance
    @instance ||= best
  end
end

示例 3: METACLASS 上的实例变量存储

class BestUser # (singleton class)
  # Memoize instance
  class << self
    def instance
      @instance ||= best
    end
  end
end

最佳答案

例2和例3完全一样。模块和类也是对象,在一个对象上定义一个单例方法实际上是在它的单例类上定义它。

话虽如此,并且由于您已经确定实例变量访问是线程安全的,因此示例 2 和 3 也是线程安全的。例1应该也是线程安全的,但不如另外两个,因为它需要手动变量同步。

但是,如果您需要利用类变量在继承树中共享这一事实,您可能必须使用第一种方法。


Ruby 语言固有的线程安全性取决于实现。

MRI,在 1.9 之前,实现了线程 at the VM level .这意味着即使 Ruby 能够安排代码执行,但在单个 Ruby 进程中并没有真正并行运行。 Ruby 1.9 使用与 global interpreter lock 同步的 native 线程.只有持有锁的上下文才能执行代码。

n, x = 10, 0

n.times do
  Thread.new do
    n.times do
      x += 1
    end
  end
end

sleep 1
puts x
# 100

x 的值在 MRI 上总是一致。然而,在 JRuby 上,情况发生了变化。同一算法的多次执行产生值 7687988894。结果可能是任何结果,因为 JRuby 使用 Java 线程,它们是真正的线程并并行执行。

就像在 Java 语言中一样,为了在 JRuby 中安全地使用线程,需要手动同步。以下代码始终为 x 生成一致的值:

require 'thread'
n, x, mutex = 10, 0, Mutex.new

n.times do
  Thread.new do
    n.times do
      mutex.synchronize do
        x += 1
      end
    end
  end
end

sleep 1
puts x
# 100

关于ruby - 线程安全 : Class Variables in Ruby,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9558192/

相关文章:

c++ - 哪些是 C++ 和 Qt 中的线程安全打印语法?

ruby-on-rails - def to_s 函数是什么?

Java GUI 线程 - SwingWorker

ruby-on-rails - ruby 检查文件是否实际被修改的最佳方法是什么?

c++ - 多线程绘图不流畅怎么解决?

php - 我如何在php多线程中使用静态方法

c++ - 在 C++ 中使用原始运算符实现异步线程的互斥

python - PySide/PyQt 中的安全和惰性方法调用

ruby - 数组的未定义方法 `each '

ruby - 理解 Ruby 类实例变量