0

クラスインスタンス変数がスレッドセーフかどうか疑問に思っています。最近、カスタム ORM のモデルによって引き起こされる d lock 問題に固執しました。(アクティブなレコードや続編モデルはありません。自分で作成した単純なバージョンの ORM です)。

シンプルにするために、ここではシンプルなバージョンをラップしました。

単純なクラス インスタンス変数を使用して、db インスタンス ( Sequel::Database オブジェクトの可能性があります) を保存します。

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

そして、このデータベースがスレッドセーフかどうかを確認するためのテスト スクリプトを作成します。

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

4

1 に答える 1

2

TestORMスレッド間で共有される定数です。つまり、同じオブジェクトを変更しています。

インスタンスを使用していた場合は、スレッドごとに 1 つずつ、異なるインスタンスを使用できます。その 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

で DB を定義することができますinitialize:

orm = TestORM.new(db)
于 2013-01-30T12:05:51.537 に答える