Pythonで排他制御を試す

threadingモジュールにセマフォがあるそうな。
LockとRLockの違い、SemaphoreとBoundedSemaphoreの違いがよくわからない。勉強不足だ。

http://docs.python.org/library/threading.html?highlight=threading#module-threading

# coding: utf-8
import threading

class Plugin(threading.Thread):
    def __init__(self, fun):
        threading.Thread.__init__(self)
        self.fun = fun
    def run(self):
        self.fun()

class ThreadGroup(object):
    # addメソッドに関数が渡された場合
    # Pluginクラスに渡して実行
    # threading.Threadの子孫クラスなら直接実行
    def __init__(self):
        self.lst = []
    def add(self, obj):
        if isinstance(obj, type(lambda:1)):
            # if obj is function
            obj = Plugin(obj)
        self.lst.append(obj)
        obj.start()
    def joinall(self):
        for t in self.lst:
            t.join()
    def __len__(self):
        return len(self.lst)




class UnsafeThread(threading.Thread):
    # 排他制御なし
    counter = 0
    def __init__(self, no):
        threading.Thread.__init__(self)
        self.no = no
    def run(self):
        print "unsafe",self.no
        for i in range(1000):
            UnsafeThread.counter += 1

class SafeThread(threading.Thread):
    # ミューテックスによる排他制御あり
    counter = 0
    mutex = threading.Semaphore(1)
    def __init__(self, no):
        threading.Thread.__init__(self)
        self.no = no
    def run(self):
        SafeThread.mutex.acquire()
        for i in range(1000):
            SafeThread.counter += 1
        SafeThread.mutex.release()


# 4つのスレッドを走らせてjoinしたあとカウンタの値を見る。
# 4000になっているはず

# unsafe
g = ThreadGroup()
for i in range(4):
    g.add(UnsafeThread(i))
g.joinall()
print UnsafeThread.counter

# safe
g = ThreadGroup()
for i in range(4):
    g.add(SafeThread(i))
g.joinall()
print SafeThread.counter

実行結果

$ python th.py 
4000
4000
$ python th.py 
4000
4000
$ python th.py 
3000
4000
$ python th.py 
4000
4000
$ python th.py 
3053
4000
$ python th.py 
3318
4000
$ python th.py 
4000
4000