二重起動を防止する(マルチスレッド プロセス編)

 題名は若干違いますがマルチスレッドの第3弾です。前回はMonitorクラスを使用して同期を取っていましたが、今回はMutexクラスを使います。MutexっていうとなんかX-Menに出てくるミュータントの仲間かなんて想像したりしましたが、MUTual EXclusion(相互排他)の略らしい。

 Mutexクラスを使ってみる。

 前回MonitorクラスでやったものをMutexクラスで行った場合に変更してみましょう。

import System
from System.Threading import *

count = 0
mut = Mutex() ←Mutexのインスタンスを作ります。

def Increment():
  global count ←countはグローバル変数であることを教えます。
  mut.WaitOne() ←Mutexの所有権を要求。
  try:
    if count <10 :
      Thread.Sleep(100)
      count = count +1
      print count
  finally:
    mut.ReleaseMutex() ←Mutexの所有権を解放

for i in xrange(100):
  th = Thread(ThreadStart(Increment))
  th.Start()

raw_input()

出力画面:
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 Monitor.Enter()に当たる部分にMutex.WaitOne()、Monitor.Exit()のところはMutex.ReleaseMutex()にします。Monitorクラスではオブジェクトへのアクセスを制限する記述だったので制限したいものをクラス化する必要がありましたが、MutexクラスはMutexのインスタンスが権利書みたいなもの。権利書がないと先に進めませんという書き方なので、クラス化する必要がありません。見方によっては平易な記述が可能になります。

 別プロセスで同期をとる

 一つのスクリプトを使って、動くPCの一連の作業をプロセスと呼びます。1つのプロセス内で複数の作業を平行して行うとき、その作業の一つをスレッドと呼び、複数の作業を平行して行うことをマルチスレッドと呼びました。 今まで説明してきたものは全て1プロセスで行われておりマルチスレッドだったわけですが、Mutexはマルチプロセスの同期を取ることも出来ます。

2種類のMutex(ローカルMutexとシステムMutex)
 Mutexには、名前のないローカルMutexと、名前付きシステムMutexの2種類があります。ローカルMutexは、現在のプロセス内部でのみ存在します。それに対して名前付きシステムMutexはWindows全体から参照でき、プロセスの動作を同期するために使用できます。システムMutexを作成するには、インスタンスを作る際に名前を指定します。具体的には次のようにやります。

   Mutex(bool, Mutexの名前)

第1引数のbool値はWaitOne()もいっしょに行って所有権を要求するかしないかをTrue, Falseで指定します。次にMutexの名前を文字列で指定します。これを使ったスクリプトの二重起動を検知するスクリプトは次のようになります。

import System
from System.Threading import *

mut = Mutex(False,"MyScript") ←名前を指定してシステムMutexのインスタンスを
                 作成しています。
if mut.WaitOne(0, False) == False : ←ここがポイント!!
  print "既に起動しています。"
  raw_input()
  exit()

print "最初に立ち上げたプログラムです。"
raw_input()

   Mutex.WaitOne(待機時間, bool)

 第1引数の待機時間は何ミリ秒Mutexの所有権がもらえるまで待つかを示してします。すなわち"0"であれば全く待たないことを意味しています。第2引数のbool値は、後で再び取得する場合はTrue、それ以外の場合はFalseに設定します。
 そしてこのアトリビュートの戻りは、Mutexの所有権をもらえればTrue、もらえなかったらFalseになります。
 以上を踏まえて考えると一つ目のスクリプト実行では次のようになります。
出力画面:
 最初に立ち上げたプログラムです。
一つ目のスクリプトをこのまま表示して置いて、もう一回スクリプトを実行させると次のようになります。
出力画面:
 既に起動しています。
このようにすれば、1回目の起動と2回目以降の起動で別の振る舞いをさせることができるため、二重起動を防止させることが出来ます。