在Ruby中双重检查锁定是否安全?

时间:2009-04-10 09:02:08

标签: ruby concurrency

当可以使用仅部分初始化的对象的引用更新共享变量时,这种article表示对某些语言/硬件组合进行双重检查锁定是不安全的。

我想知道:这也适用于Ruby吗?这是根据运行它的平台上的Ruby实现而变化的,还是语言规范中详细说明的正确行为?

3 个答案:

答案 0 :(得分:4)

Ruby的哪个实现? Ruby 1.8,1.9和JRuby具有完全不同的线程实现,因此可能无法说出来。

我没有你的问题的答案,但似乎你可能正在尝试在Ruby中编写快速并发代码。我对Ruby 1.8的经验是,这不是一个合理的目标。 Ruby 1.9可能更好,但仍然有像Python一样的全局解释器锁。

如果您正在编写Ruby代码,而您正在考虑这些可能不安全的优化以消除一些额外的性能,那么您应该考虑使用另一种语言。惯用Ruby往往在效率和速度之前强调可读性和表现力。试图提高速度和提高MRI的可靠性对我来说是一种令人沮丧的运动。

我一直在研究一个Ruby项目,刚刚进入我们正在认真研究优化的阶段。在JRuby中运行项目并用Ruby库替换Ruby中实现的瓶颈导致速度和可靠性的显着提高,而我们的工作相对较少。

JRuby并不完美,但它的Java集成已被证明是有用且简单的。如果你的项目不可能使用JRuby,或者你对C而不是Java感到满意,并确保你可以编写安全的C而没有内存泄漏,那么编写C语言扩展到Ruby 1.8或1.9可能是最好的途径。

如果这个问题完全是学术性的,我道歉。也许如果你能告诉我们你究竟想要做什么?

答案 1 :(得分:4)

在Java中进行双重检查是危险的,因为在构造函数实际完成之前可能会为变量赋值。这在Ruby中不会发生:构造对象与将函数调用的结果赋值给变量相同,因为构造函数只是普通函数。赋值只会在构造函数完成后才会发生。

在MRI上,分配是原子的。没有官方的Ruby语言或内存模型规范,但是替代实现往往会努力模仿MRI的行为,甚至是最模糊的细节。赋值语句的原子性是一个相当重要的行为,所以我希望替代Ruby实现的赋值也是原子的。

如果你不介意在争用期间意外构造两个对象,一个对象后来被垃圾收集,因为它是重复的,那么你可以使用|| =运算符,如下所示:

@singleton ||= FooBar.new

|| = atomically将给定表达式的结果赋给变量,但前提是该变量尚未设置。您最终可以使用两个FooBar.new实例,但只有一个可以访问。 Ruby on Rails在内部使用这种技术,以避免在某些地方使用互斥锁。

答案 2 :(得分:0)

Dirkjan Bussink(@dbussink)就此主题在RubyConf上发表了演讲。一旦可用,你会想看看他的演讲。