繁体   English   中英

继承运行非重入关键节的方法

[英]Inheriting methods that run a non-reentrant critical section

我有一个带有多个线程的Python程序,这些线程可以操作共享资源。 我使用一个对象对该资源建模,并使用该对象中的方法对该资源进行操作。 在关键部分中,许多动作需要作为原子动作执行。 由于这些功能遵循通用模式,因此我使用了装饰器:

def critical_section(inner):
    def outer(self, *args, **kwargs):
        self.enter()
        inner(self, *args, **kwargs)
        self.leave()
    return outer

实际的代码比这要复杂得多,例如,它可以处理异常,但这应该足以了解我在做什么。 用法示例(我简化了所有与线程相关的内容,仅检查资源所有权):

class Base:
    def __init__(self):
        self.owner = None
    def enter(self):
        assert(self.owner == None)
        self.owner = True
    def leave(self):
        assert(self.owner == True)
        self.owner = None
    @critical_section
    def foo(self):
        print('foo') # Dangerous stuff, must run atomically and not fail

具有critical_section装饰器的函数具有两个属性:

  • 该函数的代码是在持有资源锁的情况下执行的( enterleave要小心)。
  • 该函数假定资源在进入时处于稳定状态,并在退出时处于稳定状态。

第二个属性表示该锁不是可重入的锁。 在临界区中调用“临界区”函数是无效的,因为不能保证必要的不变式。

enterleave的实现检查以下属性:如果资源当前是所有者(即使是该线程本身),则线程无法调用enter ,而enter将资源的所有权授予调用线程; 对称地leave需要所有权并放弃。

在我希望拥有结构相似的多个资源之前,该体系结构一直很好地为我服务,因此我开始使用继承。

class Derived(Base):
    @critical_section
    def foo(self):
        print('fie') # Additional stuff to run first
        Base.foo(self)

现在我们要解决的问题是:装饰器从根本上讲是继承不友好的。

base = Base()
base.foo()
derived = Derived()
derived.foo()

要将呼叫derived.foo()因为当失败Base.foo()被执行时,资源已经拥有。 在调用基类的方法时,派生类可能已经破坏了该对象,这违背了Base.foo从处于已知稳定状态的对象开始的假设。

显而易见的解决方案是将每个关键部分函数转换为一对函数:外部函数(仅可从外部调用,并且永远不会在修改资源行为的类中覆盖),以及内部函数(仅可用于仅可从派生方法调用)。

  1. Python装饰器可以帮助我以最少的样板定义这样的函数对吗?
  2. 是否有一个更好的体系结构可以使进入和退出关键部分的地方的清晰度最大化,并减少误用的风险? (动态检查是好的,但是源代码的明显正确性更好。)

编辑:这是一个正确的不可重入版本。

您可以让装饰器接受参数。 所以@dec(x); def f() ... @dec(x); def f() ...将像dec(x)(f)(args)一样被调用。 因此,我们让critical_section接受一个字符串( @critical_section("Base") ),并且每个字符串有一个锁。

def critical_section(ident):
    def _critical_section(inner):
        def outer(self, *args, **kwargs):
            self.enter(ident)
            inner(self, *args, **kwargs)
            self.leave(ident)
        return outer
    return _critical_section

class Base:
    def __init__(self):
        self.owner = {}
    def enter(self, ident):
        assert(ident not in self.owner)
        self.owner[ident] = True
    def leave(self, ident):
        assert(ident in self.owner)
        del self.owner[ident]
    @critical_section("Base")
    def foo(self):
        print('foo') # Dangerous stuff, must run atomically and not fail

class Derived(Base):
    @critical_section("Derived")
    def foo(self):
        print('fie') # Additional stuff to run first
        Base.foo(self)

你好,我是昨天的。 您的根本问题是您简化了情况。 您将两件事混为一谈:进入/离开关键部分,并假设/声明资源的不变式。 但是资源的不变式在关键部分的中间也可能是正确的,而这正是您说允许Derived.foo方法调用Base.foo (在此执行过程中的某个特定时刻)时要尝试传达的内容。

您可以在Python中对此建模,但确实有点麻烦。

def critical_section(inner):
    def outer(self, *args, **kwargs):
        self.enter()
        inner(self, *args, **kwargs)
        self.leave()
    return outer

class Base:
    def __init__(self):
        self.owner = None
        self.invariants = True
    def enter(self):
        assert(self.invariants)
        self.invariants = False
        
 

 
 
  
  
 
  assert(self.owner == None)
 

 
 
        self.owner = True
    def leave(self):
        assert(self.owner == True)
        self.owner = None
        self.invariants = True
    @critical_section
    def foo(self):
        print('foo') # Dangerous stuff, must run atomically and not fail
class Derived(Base):
    @critical_section
    def foo(self):
        print('fie') # Additional stuff to run first
        self.invariants = True
        Base.foo(self)

所有者的东西应该是现实世界中的可重入锁。 进行此不变性检查,而不是通过非重新进入来防止在处于不稳定状态时修改资源。

但是,当“检查不变式”等于“我声明在代码中此刻验证了有用的不变式”时,所有这一切都很复杂,并不真正值得。 通过静态分析检查不变量,这将是另外一回事了,但是那样您就不会使用Python。


回到您的问题,即在需要时访问内部函数,Python确实使它变得非常容易。 将内部函数存储在修饰函数的属性中。

def critical_section(inner):
    def outer(self, *args, **kwargs):
        self.enter()
        inner(self, *args, **kwargs)
        self.leave()
    outer.inner_function = inner
    return outer
…
class Derived(Base):
    @critical_section
    def foo(self):
        print('fie') # Additional stuff to run first
        Base.inner.foo(self)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM