查询Python的threading.Lock是否被锁定

23

我正在运行一个线程(下面是代码),它会启动一个阻塞的子进程。为了确保其他线程不会启动相同的子进程,我在这个subprocess.call调用周围有一个锁。我还想能够终止这个子进程调用,所以我有一个从其他地方调用的停止函数。如果子进程过早地停止,我希望也释放这个锁,这就是下面的代码所做的:

class SomeThread(threading.Thread):
   def run(self):
      aLock.acquire()
      self.clip = subprocess.call([ 'mplayer', 'Avatar.h264'], stdin=subprocess.PIPE)
      aLock.release()
   def stop(self):
      if self.clip != None and self.clip.poll() == True:
         try:
            self.clip.send_signal(signal.SIGINT)
         except:
            pass
      aLock.release()

然而,根据此处的文档,对已经释放的锁再次调用release()将会引发异常:

A RuntimeError is raised if this method is called when the lock is unlocked.

是否有类似于 aLock.isLocked() 的查询函数?

1个回答

52
当然可以!
>>> from threading import Lock
>>> x = Lock()
>>> x.locked()
False
>>> x.acquire()
True
>>> x.locked()
True

您还可以进行非阻塞的获取:

x.acquire(False)
x.release()

在这种情况下,如果 x 是未锁定的,则代码会获取并释放它。但是,如果 x 已经被锁定,那么非阻塞式的获取将立即返回(并返回 False),然后我们再次释放它。但是这存在竞争的问题!没有任何东西可以阻止其他线程在这两行之间释放锁。
同样,检查 .locked() 也是如此。它只告诉您 .locked() 执行时锁的状态。到您执行下一个语句时,它可能已经不再是真实状态了。
顺便说一下,run() 的主体最好使用锁作为“上下文管理器”来编写,就像这样:
def run(self):
    with aLock:
        self.clip = subprocess.call([ 'mplayer', 'Avatar.h264'], stdin=subprocess.PIPE)

这将为您执行acquire()/release()配对操作,并且在with块的主体中引发意外异常时更加健壮(如果主体由于任何原因退出,则Python会尽其所能释放锁定)。

4
就像电影《盗梦空间》一样,我们需要深入到更深层次。 - puk
12
为什么文档没有提到locked()函数呢? - ChickenFeet
文档中确实提到了它,但很容易被忽略。它在底部,以与其余函数不同的格式呈现:locked() 如果已获取锁,则返回true。 - porgull
1
@ChickenFeet threading.lockmultiprocessing.lock不同, 在multiprocessing.lock中没有locked()方法。 - PersianMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接