如何避免在Python中使用锁、继承和线程初始化类属性时出现死锁?

2024-10-01 17:24:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图实现线程安全代码,但遇到了一些简单的问题。我找了又找不到解决办法。在

让我展示描述问题的抽象代码:

import threading

class A(object):
  sharedLock = threading.Lock()
  shared = 0

  @classmethod
  def getIncremented(cls):
    with cls.sharedLock:
      cls.shared += 1
      return cls.shared

class B(A):
  pass

class C(A):
  @classmethod
  def getIncremented(cls):
    with cls.sharedLock:
      cls.shared += B.getIncremented()
      return cls.shared

我想定义类A来继承许多子类,例如枚举或惰性变量的特定用途。我已经做了单线程版本现在要更新多线程。在

该代码将给出如下结果:

^{pr2}$

我的意思是,class A中的lock是class B中的锁,因此它是错误的,因为第一次进入{}将同时锁定{}和{}。如果C将使用B,则会导致去锁。在

我可以使用RLock,但它是无效的编程模式,不确定它是否不会产生更严重的死锁。在

在初始化类的过程中,如何将sharedLock值更改为新锁,使id(A.sharedLock) != id(B.sharedLock)CBC相同?

如何在泛型中钩住python中的类初始化以更改某些类变量?

这个问题不太复杂,但我不知道该怎么办。在


Tags: 代码importidreturndefwith线程class
3条回答

正如您所注意到的,如果您将共享锁公开为类属性,那么这些锁将由子类共享。在

您可以通过重新定义每个子类上的锁来解决这个问题:

class B(A):
  sharedLock = threading.Lock()

您甚至可以使用元类来实现这一点(请不要)。在我看来,你从一个错误的角度来看待这个项目。在

如果将锁显式地分配给实例(而不是类),则此任务更容易完成。在

^{pr2}$

当然,您会遇到一个“问题”,即必须显式地为每个实例传递锁。传统上,这是使用factory pattern来解决的,但是在python中,您可以简单地正确地使用函数:

from functools import partial
A_with_mylock= partial(A, my_lock)
a2= A_with_mylock()

I want inherit parent share variables except shared parent locks

你不能这样做。它使访问“共享变量”不是线程安全的。在


sharedLock保护shared变量。如果相同的shared变量可以在递归调用中修改,那么您需要RLock()。这里shared表示在所有子类之间共享。在

看起来您希望使用独立函数(或静态方法)而不是classmethod:

def getIncremented(_lock=Lock(), _shared=[0]):
    with _lock:
      _shared[0] += 1
      return _shared[0]

因此,所有类都使用相同的shared变量(以及相应的lock)。在

如果希望每个类都有自己的shared变量(这里shared表示在这个特定类的实例之间共享),那么不要使用可能遍历祖先的cls.shared来获取它。在

为了暗示子类不应该直接使用变量,可以使用私有变量的语法:

^{pr2}$

如果子类重写了使用__shared的方法,那么它不会在代码中意外地直接使用A.__shared。在

这是解决方案-这允许每个类单独锁,因为它是在类构造函数级别(元类)上实现的。感谢您的所有提示和帮助,以实现这段代码,它看起来非常好。在

我也可以被损坏的变量,但需要使用硬代码''u A_uulock'什么可能是有问题的,没有测试我。在

import threading

class MetaA(type):
  def __new__(self, name, bases, clsDict):
    # change <type> behavior
    clsDict['_lock'] = threading.Lock()
    return super(MetaA, self).__new__(self, name, bases, clsDict)

class A(object):
  __metaclass__ = MetaA

  @classmethod
  def getLock(cls):
    return cls._lock

class B(A):
  pass

print 'id(A.getLock())', id(A.getLock())
print 'id(B.getLock())', id(B.getLock())
print A.getLock() == B.getLock()

相关问题 更多 >

    热门问题