PyQt:QMutexLocker未在异常时发布

Rol*_*lle 5 python pyqt

我有以下代码:

def query(self,query):
  lock = QMutexLocker(self.mutex)
  reply = self.conn.query(query)
  if (re.search("error", reply) != None):
    raise GeneralError("Query error")

  #more code...  
  return reply
Run Code Online (Sandbox Code Playgroud)

现在,如果抛出异常,锁似乎不会被删除,导致互斥锁未被释放.我可以在任何地方做"del lock",但这会消除qmutexlocker的全部意义.这与Python垃圾收集有关吗?如果是这样,那必然意味着QMutexLocker在Python中根本不可用?

jdi*_*jdi 12

您没有正确使用QMutexLocker.像上下文管理器一样使用它:

from PyQt4.QtCore import QMutex, QMutexLocker

def bad_lock(aLock):
    locker = QMutexLocker(aLock)
    print "Locked"
    raise RuntimeError("Test exception")

    return "Should not get here"

def good_lock(aLock):
    with QMutexLocker(aLock):
        print "Locked"
        raise RuntimeError("Test exception")

    return "Should not get here"

lock = QMutex()

bad_lock(lock)
print lock.tryLock()
# False

lock.unlock()

good_lock(lock)
print lock.tryLock()
# True
Run Code Online (Sandbox Code Playgroud)

在测试中,您在第一个示例中看到,锁定返回仍然处于锁定状态.在第二种情况下,当引发异常时,上下文管理器在离开函数之前释放锁.

在C++中使用时,我确信QMutexLocker可以完成预期的操作,并在范围结束时解锁.但是在Python中,正如您所发现的那样,不应该依赖垃圾收集器来解锁.通过with声明的上下文管理器是完美的.你可以通过这个类的C++示例来表明它只是在函数的顶部创建.而python版本同时具有an __enter____exit__方法.

最后,with上下文允许您将关键代码块包装在一个锁中,以限制需要锁定的数量,因此您可以执行以下操作:

def good_lock(aLock):

    # do a bunch of stuff here
    ...

    # critical section
    with QMutexLocker(aLock):
        # do critical stuff here
        ...

    # do other stuff here
    ...

    return True
Run Code Online (Sandbox Code Playgroud)


msw*_*msw 0

如果您希望在引发异常之前释放互斥体,请释放它:

\n\n
def query(self, query):\n    lock = QMutexLocker(self.mutex)\n    reply = self.conn.query(query)\n    if re.search("error", reply):\n        lock.unlock()\n        raise GeneralError("Query error")\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果你希望当lock它超出范围时立即被释放,那么你对解释器的期望太高了。既然您确切地知道何时以及为何应该释放锁,那就这么做吧。

\n\n

作为一般规则 \xe2\x80\x94 Python 或其他地方 \xe2\x80\x94 你应该始终有一个互斥体绑定尽可能小的操作。我假设您知道无论查询正在做什么实际上都需要保护,并且在调用self.conn.query.

\n\n

添加回应评论

\n\n

这是一个公平的观点,“一定意味着 QMutexLocker 根本不可用”,我确实错过了。我假设您指的是PySide.QtCore.QMutexLocker,它提出了不太可能的声明:

\n\n
\n

现在,当 PySide.QtCore.QMutexLocker 对象被销毁时(当函数返回时,因为 locker 是一个自动变量),互斥锁将始终被解锁。

\n
\n\n

这不太可能,因为Python中没有auto变量存储类这样的东西。我怀疑,经过进一步调查,这将被证明是“让我们包装一个 C++ 库并假设作用域语义起作用”。如果这个猜测是正确的,您可以使用with 语句来更好地保证可靠的解锁。

\n

  • **这是一个明显糟糕的答案。** 在 `with:` 上下文之外使用 `QMutexLocker` 会使使用 `QMutexLocker` 的整个意义失效。如果你打算这样做,你最好使用轻量级的“QMutex”。当然,你也不应该这样做;你应该只在“with:”上下文中使用“QMutexLocker”。当尝试从引发的异常中恢复时,任何其他锁定模式都会引发竞争条件和死锁。 (4认同)