33

我正在尝试使用 with 语句进行一些共享锁定

def someMethod(self, hasLock = False):
     with self.my_lock:
         self.somethingElse(hasLock=True)


def somethingElse(self, hasLock = False):
    #I want this to be conditional...
    with self.my_lock:
          print 'i hate hello worlds"

有道理?如果我还没有锁,我基本上只想这样做。

除了能够做到这一点之外,这是一个糟糕的设计吗?我应该只是获取/释放自己吗?

4

5 回答 5

59

只需使用threading.RLock可重入的,这意味着它可以被同一个线程多次获取。

http://docs.python.org/library/threading.html#rlock-objects

为清楚起见,RLock在语句中使用了with,就像在您的示例代码中一样:

lock = threading.RLock()

def func1():
    with lock:
        func2()

def func2():
    with lock: # this does not block even though the lock is acquired already
        print 'hello world'

至于这是否是糟糕的设计,我们需要更多的上下文。为什么这两个函数都需要获取锁?什么时候被func2其他东西调用func1

于 2011-03-03T19:47:47.970 回答
7

Pythonor短路的,因此您可以使锁定有条件:

def somethingElse(self, hasLock = False):
    #I want this to be conditional...
    with hasLock or self.my_lock:
          print 'i hate hello worlds'

不幸的是,这并不那么容易,因为布尔值不是with语句的有效返回。您需要使用__enter__and创建一个类__exit__来包装布尔True值。

这是我尚未测试过的一种可能的实现。

from contextlib import contextmanager

@contextmanager
def withTrue():
    yield True

def withbool(condition):
    if condition:
        return withTrue()
    return False

def somethingElse(self, hasLock = False):
    with withbool(hasLock) or self.my_lock():
          print 'i hate hello worlds'

对于如此简单的事情,这是很多样板,因此 RLock 解决方案看起来像是赢家。但是,此解决方案可能在不同的上下文中很有用。

于 2011-03-03T19:49:29.327 回答
2

使用 with 语句比只使用acquire()release()函数更好。这样,如果发生错误,锁将被释放。

于 2011-03-03T19:45:43.487 回答
2

为什么不:

def someMethod(self):
     with self.my_lock:
         self.somethingNoLock()

def somethingElse(self):
    with self.my_lock:
         self.somethingNoLock()

def somethingNoLock(self):
    print 'i hate hello worlds"

请注意,虽然someMethodsomethingElse在我的解决方案中相同,但通常它们会有所不同。您可以放置​​另一个包装器,somethingNoLock这样锁的获取和释放就不会重复多次。

这要简单得多。仅仅因为可以使用重入式锁锤,我不建议在有更直接、更不易碎的方式来钉它时使用它。

对 rlock 更具体的批评是,创建可重入锁的行与以可重入方式获取锁的代码相距甚远。如果有人说将可重入锁与另一个不可重入的锁合并或以其他方式更改创建锁的行,这有点脆弱。

于 2016-07-13T10:09:06.793 回答
1

with语句是实现锁定的好方法,因为锁定是一种完美的资源获取模式。尽管您当前的示例不起作用。您需要if围绕with.somethingElse()

于 2011-03-03T19:48:57.473 回答