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)」という自作のメソッドにより、出力されている。