Threadクラスでスレッド生成、およびMutexクラスでスレッドセーフな排他的アクセス

はてなブックマークに追加はてなブックマーク Yahoo!ブックマークに登録 ニフティクリップに追加 Livedoor クリップに追加 BuzzurlにブックマークBuzzurlにブックマーク Twitterに投稿  

Rubyでのマルチスレッド操作を少し勉強しました。
Threadクラスでただ単にスレッドを生成して実行した場合、共有リソースへの並列アクセスで、共有リソースのデータ不整合など問題が起こる場合がある。
Mutexを用いると排他的アクセスを実現し、データの整合性を保つことができます。
以下、実験してみたコード。


Thread単純実行、Threadを使わずループ、Mutexの3パターン

# スレッドのリストのうち、最初の3つを確認
def thread_list(threads)
  num = 0
  threads.each do |t|
    p t
    num += 1
    break if num == 3
  end
end
 
# スレッドでの並列処理の場合、共有リソースへのアクセス時に注意する
# Mutexを使うと排他処理になり、共有リソースへ安全にアクセスできる。
ThreadNum = 10000
 
puts "スレッドセーフでなく、共有リソースを破壊する例"
class Count
  @@count = 0
  def count_up
    @@count += 1
  end
  def self.count
    return @@count
  end
  def self.count=(val)
    @@count = val
  end
end
 
puts Count.count
threads = []
# スレッドをThreadNum個作って、配列に追加
for i in 1..ThreadNum
  t = Thread.new do
    Count.new.count_up
  end
  threads << t
end
 
# ThreadNum個のスレッド実行が終了するのを待つ。
for i in 1..ThreadNum
  threads[i - 1].join
end
# スレッドを確認
thread_list(threads)
puts Count.count  # ThreadNum個になるはずだが…足りない
 
puts "--- スレッドを作らないで、単にループでカウントアップ ---"
Count.count = 0 # countをリセット
puts Count.count
for i in 1..ThreadNum
  Count.new.count_up
end
puts Count.count  # ThreadNum個になっている
 
puts "--- Mutexを用いて、排他的アクセス ---"
require 'thread'
class CountByMutex
  @@count = 0
  @@mutex = Mutex.new
  def count_up
    # mutexオブジェクトで排他的アクセスにする
    @@mutex.synchronize do
      @@count += 1
    end
  end
  def self.count
    return @@count
  end
end
 
puts CountByMutex.count
threads = []
# スレッドをThreadNum個作って、配列に追加
for i in 1..ThreadNum
  t = Thread.new do
    CountByMutex.new.count_up
  end
  threads << t
end
 
# ThreadNum個のスレッド実行が終了するのを待つ。
for i in 1..ThreadNum
  threads[i - 1].join
end
# スレッドを確認
thread_list(threads)
puts CountByMutex.count  # ThreadNum個になる


実行結果

スレッドセーフでなく、共有リソースを破壊する例
0
#<Thread:0x283e5a8 dead>
#<Thread:0x283e558 dead>
#<Thread:0x283e4f4 dead>
9940
--- スレッドを作らないで、単にループでカウントアップ ---
0
10000
--- Mutexを用いて、排他的アクセス ---
0
#<Thread:0x2afc4ac dead>
#<Thread:0x2afc420 dead>
#<Thread:0x2afc394 dead>
10000

排他制御の書き方は、こんな感じで良いのだろうか・・・(あんま自信ない)
Rubyの排他制御なメソッドの記述は、Javaのsynchronizedメソッドの書き方に少し似ています。

参考にしたページ:
逆引きRuby - スレッド
Thread - Rubyリファレンスマニュアル
第19章 スレッド(このページはムズイ・・・)


日時: 2009年08月18日 21:30
コメントを投稿






トラックバック

■この記事のトラックバックURL:
http://www.mapee.jp/mpe334/mt-tb.cgi/491

この記事にトラックバックされる方は、参照先が分かるようにするために、「Threadクラスでスレッド生成、およびMutexクラスでスレッドセーフな排他的アクセス」へのリンクをお願いいたします。
以下のHTMLタグをトラックバック送信元ページ内に挿入して下さい。



※この記事へのリンクがない、また関連のないページからのトラックバックは反映されませんので、ご了承下さい。






あわせて読みたいブログパーツ
フィードメーター - Ruby勉強ルーム