0

データベースがロックされていることをテストしたいとします。

$transaction = Thread.new  {
    Rails.logger.debug 'transaction process start'
    Inventory.transaction do
      inventory.lock!
      Thread.stop
      inventory.units_available=99
      inventory.save
    end
  }
  $race_condition = Thread.new  {
    Rails.logger.debug 'race_condition process start'
    config = ActiveRecord::Base.configurations[Rails.env].symbolize_keys
    config[:flags] = 65536 | 131072 | Mysql2::Client::FOUND_ROWS
    begin
      connection = Mysql2::Client.new(config)

      $transaction.run
      $transaction.join
    rescue NoMethodError
    ensure
      connection.close if connection
    end
  }
  Rails.logger.debug 'main process start'
  $transaction.join
  Rails.logger.debug 'main process after transaction.join'
  sleep 0.1 while $transaction.status!='sleep' 
  Rails.logger.debug 'main process after sleep'
  $race_condition.join
  Rails.logger.debug 'main process after race_condition.join'

理論的には、トランザクションスレッドを実行し、次にwait(Thread.stop)を実行すると、メインプロセスはスリープ状態になっていることを確認し、競合状態スレッド(ロックされたテーブルのデータを変更しようとします)を開始すると思います。それが実際に機能するとき)。次に、競合状態は、それが行われた後、トランザクションスレッドを続行します。

奇妙なのはトレースです

main process start
transaction process start
race_condition process start

nodejsから来ているので、スレッドはユーザーフレンドリーではないようです。しかし、これを行う方法が必要です。

データベースをロックしてから、別のスレッドでデータベースを変更する簡単な方法はありますか?

4

2 に答える 2

0

Thread.new は、スレッドを自動的に開始します。しかし、それはそれが実行されているという意味ではありません。これは、運用システム、ruby または jruby、コア数などによって異なります。

あなたの例では、メイン スレッドは $transaction.join まで実行され、その後、偶然にトランザクション スレッドが開始されます。他の両方がブロックされているため、Thread.stop が引き続き実行され、「$race_condition」スレッドが開始されます (以前に開始された可能性があります)。

それで、あなたのログを説明します。

スレッドが終了するまで待機する$transaction.join が 2 つ
ありますが、スレッドは 1 回しか終了できません。

テストでは、ある種の明示的な同期が必要です。これにより、race_thread は、transaction_thread がトランザクションの途中にあるときに正確に書き込むことができます。Mutex を使用してこれを行うことができますが、何らかのメッセージ パッシングの方が適しています。次のブログ投稿が役立つ場合があります。

http://www.engineyard.com/blog/2011/a-modern-guide-to-threads/

于 2012-09-29T00:10:24.077 に答える
0

リソースを「相互排他的」にするには、Mutexクラスを使用し、同期メソッドを使用して、1 つのスレッドがそれらを使用している間、リソースをロックする必要があります。次のようなことをしなければなりません:

semaphore = Mutex.new

Thread インスタンス内で使用します。

$transaction = Thread.new  { 
  semaphore.synchronize{
  # Do whatever you want with the *your shared resource*
  }
}

これにより、デッドロックを防ぐことができます。

お役に立てれば。

于 2012-09-28T21:57:40.600 に答える