如何再次从类中调用已锁定的代码块?

时间:2011-12-29 13:49:22

标签: python locking

我正在使用类中的锁来避免多个线程将相同的元素添加到列表中两次。但是,当我想从类本身访问一个受锁保护的方法时,我的类就会卡住。

该类看起来像这样(简化,所以它不再有意义了):

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

在那里你可以看到所有的方法都有效,但是当一个新的元素应该从getFromDb(从add里面的锁定块调用)中添加一个新元素时,它自己再次调用add,申请无法继续。

除了在getFromDb中直接填写列表而不使用add之外,还有其他方法吗?这不会那么好,因为add检查重复项(已经在这个非常基本的例子中)。

2 个答案:

答案 0 :(得分:2)

在我看来,你需要两个版本的add()---一个获取锁,另一个不获取。 get()应该调用没有获取锁的版本,因为它已经有锁。

或者,您是否考虑使用RLock object(根据我对文档的阅读)跟踪在线程中获取锁定的递归尝试?

答案 1 :(得分:1)

您需要一个递归锁定。 python的threading - see here中有一个。