RubyでSingletonパターン考察3・Mutexでマルチスレッド対応
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
Singletonインスタンスが生成されているかどうかをif 条件文で判定して、Singletonパターンをマルチスレッドに対応させることを考えてみた。
その場合、Mutexクラスを使えばできそうだ・・・ということで、Threadクラスでスレッド生成、およびMutexクラスでスレッドセーフな排他的アクセスで書いたように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の場合の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)」という自作のメソッドにより、出力されている。