我有以下伪代码:
class A:
mutex lockForB
class B:
def __init__(self, A): //the type of A is class A
lock(A.lockForB)
# ...
unlock(A.lockForB)
# other function have the same locking
我从oop的角度理解使用这样的设计是非常糟糕的,但如果我在B类中创建锁,我将无法锁定B类的创建者。有没有更好的设计呢?提前谢谢。
答案 0 :(得分:3)
我不知道你想要完成什么。类级别锁定不太可能是您想要的,但您的伪代码与实际代码的距离不是很远,所以我只填写空白。老实说,如果你不知道你试图同步访问它,那将是一个帮助你的挑战。
class A:
lockForB = threading.RLock()
class B:
def __init__(self):
with A.lockForB:
# do init stuff
def othermethod(self):
with A.lockForB:
# do other stuff
这样代码就可以了。 lockForB只是A上的一个类级别属性,因此它在A的所有实例之间共享。但是,在我看到人们使用这样的类级别锁的情况下,通常是为了防止拥有该锁的类被放入一个不一致的状态,你有两个看似无关的类共享一个锁。
如果没有上下文来帮助理解你试图同步访问它的内容,很难告诉你为什么不能这样写:
class C:
lock = threading.RLock()
def __init__(self):
with self.lock:
# do stuff
def othermethod(self):
with self.lock:
# do other stuff
答案 1 :(得分:1)
通常,您应该仅在关键部分的边界或共享资源的使用周围放置锁。你应该考虑一下你试图保护它免受同时访问并保护它。例如,如果A类具有放置和读取项目的队列,那么您应该保护对该特定资源的访问权限。由于OOP规定只能通过类方法访问此类资源,因此只有A类应该保护它:
class A(object):
def __init__(self, *args, **kws):
# do the initialization
self._my_queue = Queue()
self._lock = Lock()
def do_something(self):
# do initial calculations
self._lock.acquire()
item = self._my_queue.get()
self._lock.release()
# do other things
因此,B类应该调用A类方法,它将是线程安全的。如果B类有自己的关键部分,那么使用多个锁是非常好的:
class B(object):
def __init__(self, *args, **kws):
# do the initialization
self._lock = Lock()
self.a = A()
def do_something_with_a(self):
# initial calculations
self._lock.acquire()
# Critical section
result = self.a.do_something()
# do something with result
self._lock.release()
# continue the code
这样每个类都可以保护自己的关键部分和共享资源,而且不需要破坏类接口。
如果你需要保护类的C'tor,那么你需要一个模块的全局锁,在类的范围之外创建和初始化,或者将锁添加到Class对象(就像静态成员一样)在C ++和Java中而不是实例本身:
class B(object):
def __init__(self, *args, **kws):
if not hasattr(self.__class__, "_lock"):
self.__class__._lock = Lock()
# works with Python 2.6+ for earlier version use try-finally
with self.__class__._lock:
# Your initialization
这将保护你的C'tor