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

スポンサーリンク
 
スポンサーリンク