繁体   English   中英

ruby类实例变量不是线程安全吗?

[英]ruby class instance variable not thread safe?

我只是想知道类实例变量是否是线程安全的。 最近,我陷入了由自定义ORM模型引起的数据库锁定问题。 (无论如何,没有活动记录或续集模型,只是我自己创建的ORM的简单版本)。

为了简单起见,我在这里只包含了一个简单的版本:

我使用一个简单的类实例变量来保存数据库实例(可能是一个Sequel :: Database对象)。

class TestORM
  class << self
    attr_accessor :db 
    def self.db=( db )
      @db = db
    end 
  end 
end

我为它创建一个测试脚本来验证这个db是否是线程安全的。

require 'test_orm.rb'
t1 = Thread.new do  
  db = 'db string 1'
  p "Thread 1: before assign, thread = #{Thread.current.object_id}, TestORM.db.object_id = #{TestORM.db.object_id}"
  TestORM.db = db
  p "Thread 1: after assign, thread = #{Thread.current.object_id}, TestORM.db.object_id = #{TestORM.db.object_id}"
  sleep( 0.5 )
  p "Thread 1: TestORM.db.object_id =  #{TestORM.db.object_id}"
end 
t2 = Thread.new do  
  db = 'db string 2'      
  p "Thread 2: before assign, thread = #{Thread.current.object_id}, TestORM.db.object_id = #{TestORM.db.object_id}"
  TestORM.db = db
  p "Thread 2: after assign, thread = #{Thread.current.object_id}, TestORM.db.object_id = #{TestORM.db.object_id}"
  sleep( 0.5 )
  p "Thread 2: TestORM.db.object_id =  #{TestORM.db.object_id}"
end

t1.join
t2.join

运行上面的代码产生以下结果:

"Thread 1: before assign, thread = 70332471940100, TestORM.db.object_id = 4"
"Thread 2: before assign, thread = 70332471939980, TestORM.db.object_id = 4"
"Thread 1: after assign, thread = 70332471940100, TestORM.db.object_id = 70332471939840"
"Thread 2: after assign, thread = 70332471939980, TestORM.db.object_id = 70332471939520"
"Thread 1: TestORM.db.object_id =  70332471939520"
"Thread 2: TestORM.db.object_id =  70332471939520"

从上面的结果看,类实例变量似乎不是线程安全的,因为线程2覆盖了线程1的TestORM.db实例。

这种包装的任何提示或任何解决方案?

红宝石版:红宝石1.9.2p320

TestORM是线程之间的常量共享。 也就是说,您正在更改同一个对象。

如果您使用的是实例,则可以使用不同的实例,每个线程一个。 由于您创建了该ORM,我建议您将实例用于不同的DB; 所以你的代码看起来像这样:

require 'test_orm.rb'
t1 = Thread.new do  
  db = 'db string 1'
  orm = TestORM.new   
  p "Thread 1: before assign, thread = #{Thread.current.object_id}, orm.db.object_id = #{orm.db.object_id}"
  orm.db = db
  p "Thread 1: after assign, thread = #{Thread.current.object_id}, orm.db.object_id = #{orm.db.object_id}"
  sleep( 0.5 )
  p "Thread 1: orm.db.object_id =  #{orm.db.object_id}"
end 
t2 = Thread.new do  
  db = 'db string 2'
  orm = TestORM.new   
  p "Thread 2: before assign, thread = #{Thread.current.object_id}, orm.db.object_id = #{orm.db.object_id}"
  orm.db = db
  p "Thread 2: after assign, thread = #{Thread.current.object_id}, orm.db.object_id = #{orm.db.object_id}"
  sleep( 0.5 )
  p "Thread 2: orm.db.object_id =  #{orm.db.object_id}"
end

您可能希望在initialize定义数据库:

orm = TestORM.new(db)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM