2011-12-29 4 views
1

複数のスレッドが同じ要素をリストに2回追加しないようにするために、クラス内でロックを使用しています。しかし、クラス自体の中からロックで保護されたメソッドにアクセスしたい場合、クラスが止まってしまいます。既にロックされたコードブロックをクラスから呼び出すにはどうすればいいですか?

クラスは、この(それはもうあまり意味がありませんので、単純化)のようになります。

import threading 

class List(object): 
    def __init__(self): 
     self.list = [] 
     self.lock = threading.Lock() 

    def add(self, element): 
     print("adding") 
     with self.lock: 
      if not element in self.list: 
       self.list.append(element) 

    def get(self): 
     print("getting") 
     with self.lock: 
      # Try to get more elements, might fail 
      if len(self.list) == 0: 
       self.getFromDb() 

      if len(self.list) > 0: 
       el = self.list.pop() 
       return el 
      else: 
       return None 

    def getFromDb(self): 
     print("getting from db") 
     # Emulate an hardcoded database ;) 
     self.add("i am new") 
     # Here we will enter a block that is already locked by 
     # the thread who called get() so my method waits 
     # infinitely 

それが新しい要素を追加したいとき、それが立ち往生ように、次のテストファイルは完了しません。リスト:

list = List() 
print("= 1 =") 
list.add("hi") 
print("= 2 =") 
print(list.get()) 
print("= 3 =") 
print(list.get()) 
print("= 4 =") 

出力は次のとおりです。

あり
= 1 = 
adding 
adding 
= 2 = 
getting 
hi 
= 3 = 
getting 
getting from db 
adding 

あなたはそのすべてのメタを見ることができますodsは動作していますが、addを再度呼び出すgetFromDbaddのロックされたブロックから呼び出された)から新しい要素を追加すると、アプリケーションを続行できません。

addを使用せずにgetFromDbに直接リストを入力する以外の方法はありますか? addが重複をチェックしているので(これは非常に基本的な例です)、これは素晴らしいことではありません。

+0

Lockの代わりにRLockをお探しですか? –

答えて

1

再帰的なロックが必要です。 pythonのthreading - see hereに1つあります。

2

add()の2つのバージョンが必要です。つまり、ロックを取得するものとそうでないものがあります。 get()は既にロックを持っているので、ロックを取得しないバージョンを呼び出す必要があります。

また、RLock objectを使用して、スレッド内のロックを取得する再帰的な試みを(スレッドの読者に基づいて)把握していますか?

関連する問題