在Ruby中为mutex使用类实例变量
注意:下面显示的代码摘要不是我遇到问题的代码的精华。 我已经在这里留下了这个原始摘要,因为其他人已经回答了,但实际的代码显示在我在下面提供的答案中。
我无法将其与一个小的失败测试用例隔离开来,但是我使用以下常规构造失败了:
class Foo @mutex = Mutex.new .... def self.bar @mutex.synchronize { ... } end end
如果我创建多个线程来调用Foo.bar
,有时@mutex
将在bar
评估为nil
。 如果我使用常量(例如MUTEX)而不是实例变量,我没有这个问题。
我不知道它是否重要,但我在JRuby上使用多核机器运行。
我很感激如何解决问题的任何解释或帮助。
更新:我认为这与自动加载有关。 使用Rails,我能够在以下Rails自动加载目录之一中使用以下foo.rb
内容重现类似问题:
class Foo @mutex = Mutex.new def self.bar @mutex.synchronize {} end end
当我在Rails控制台中执行以下操作时:
1.upto(4).map { Thread.new { Foo.bar }}.map(&:join)
我收到以下错误:
RuntimeError: Circular dependency detected while autoloading constant Foo from /Users/palfvin/.rvm/gems/jruby-1.7.10@javlats/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:461:in `load_missing_constant' from /Users/palfvin/.rvm/gems/jruby-1.7.10@javlats/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:184:in `const_missing' from (irb):1:in `evaluate'
这个行为在CRuby(MRI Ruby)中是相同的。
它是否发生在类变量中? @@mutex
。 在线程之间创建新的类实例可能存在竞争条件,并且@mutex
的新副本尚未准备就绪。 但是,常量和类变量在类和子类的副本之间共享。 另外,如果将@mutex
初始化代码放在memoized方法中,例如:
def self.mutex @mutex ||= Mutex.new end
虽然自动加载在Rails中确实不是线程安全的,就像它在Ruby 1.9中一样(在Ruby 1.9中是自动加载线程安全吗? ),我遇到的问题不是由于那个问题而我所拥有的代码不是代码的实例我在上面展示了,而是以下的一个实例:
class Foo @mutex = Mutex.new def self.bar @mutex.synchronize { } end end class Foobar < Foo ; end Foobar.bar
问题是当从超类执行方法时, self
的值保持不变,因此@mutex
中Foo.bar
的值在Foobar
对象的上下文中解释,而不是Foo
对象的值。
通过为互斥锁使用类变量(例如@@mutex
)可以避免此问题。
- NoMethodError:在tomcat上部署rails app时的relative_url_root
- 使用JRuby将Ruby on Rails应用程序的所有.rb文件编译为.class,将其打包成.war并部署到Java appserver中
- 使用JRuby(Hpricot?)解析XML,使用之类的标签
- 编写Logstash GEM会出现错误:未定义的局部变量或方法
- 如何在使用JRuby或bundle exec时使用rspec启用颜色?
- Nailgun模式下JRuby 1.7上的Rails应用程序无法启动
- Jruby中的Java数组
- JRuby / Windows和(本机)扩展如何区分它们?
- 如何提高jRuby加载时间?