Singletonインスタンスが生成されているかどうかをif 条件文で判定して、Singletonパターンをマルチスレッドに対応させることを考えてみた。
その場合、Mutexクラスを使えばできそうだ・・・ということで、Threadクラスでスレッド生成、およびMutexクラスでスレッドセーフな排他的アクセス - Ruby入門勉強ルームで書いたようにMutexでSingletonインスタンスを取得するメソッドを、synchronizeで排他的アクセスにしてみた。
Mutexを用いたSingletonパターン
require 'thread'
require 'pp'
# スレッドのリストのうち、最初の3つを確認
def thread_list(threads)
num = 0
threads.each do |t|
p t
num += 1
break if num == 3
end
end
class Singleton
@@singleton = nil
@@mutex = Mutex.new
# new をprivateにする
private_class_method(:new)
def self.singleton
@@mutex.synchronize do
if @@singleton == nil
sleep 3
@@singleton = new
end
end
return @@singleton
end
end
threads = []
for i in 1..3
t = Thread.new do
obj = Singleton.singleton
puts "#{obj.object_id}\n"
end
threads << t
end
pp Thread.list
threads.each do |th|
th.join
end
pp Thread.list
thread_list(threads)
実行結果
[#<Thread:0x28f981c sleep>, #<Thread:0x28f9894 sleep>, #<Thread:0x28f9920 sleep>, #<Thread:0x284c748 run>] 21481110 21481110 21481110 [#<Thread:0x284c748 run>] #<Thread:0x28f9920 dead> #<Thread:0x28f9894 dead> #<Thread:0x28f981c dead>
Mutexオブジェクトを作り、synchronizeメソッドを用いると、複数のインスタンスを確実に生成させようとするために、if 条件式の直後に「sleep 3」を入れていても、マルチスレッドでの単一インスタンス取得が実現できています。
RubyでSingletonパターン考察1 - Ruby入門勉強ルームの場合のMutexを使わないコードでは、Singletonパターンなのに、マルチスレッドでインスタンスが複数生成されていました。
Thread.listについて
Thread.listは、存在するスレッドのオブジェクトを配列で出力する。
スレッドオブジェクトは、run, sleep, deadなどの状態を保持しています。
ちなみに、Thread.listでは、メインスレッドもリストに現れるようです。
最初に4つ出力されたスレッドうち、runしているのがメインスレッド。
ほかのスレッドは、「sleep 3」により寝ている。
Thread#joinで、すべてのスレッド実行が終了するのを待った後、「Thread.list」を出力していますが、Thread.listでは、deadしたスレッドは出てこないようです。
deadしたスレッドは、「thread_list(threads)」という自作のメソッドにより、出力されている。
■この記事のトラックバックURL:
http://www.mapee.jp/mpe334/mt-tb.cgi/494