Python PyQt:QMutexLocker未在异常时释放

Python PyQt:QMutexLocker未在异常时释放,python,pyqt,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 现在,如果抛出异常,锁似乎不会被删除,因为互斥锁不会被释放。当然,我可以在

我有以下代码:

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

现在,如果抛出异常,锁似乎不会被删除,因为互斥锁不会被释放。当然,我可以在任何地方使用“dellock”,但这就剥夺了qmutexlocker的全部功能。这与Python垃圾收集有关吗?如果是这样,那一定意味着QMutexLocker在Python中根本不可用?

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

def query(self, query):
    lock = QMutexLocker(self.mutex)
    reply = self.conn.query(query)
    if re.search("error", reply):
        lock.unlock()
        raise GeneralError("Query error")
如果您希望当
lock
超出范围时,它会立即被释放,那么您对解释器的期望太高了。既然您确切地知道何时以及为什么应该释放锁,那么就这样做吧

作为一般规则——Python或其他地方——您应该始终拥有一个尽可能小的操作的互斥绑定。我假设您知道,无论查询在做什么,实际上都需要保护,在调用
self.conn.query
之后,它仍然需要保护

为回应评论而添加的内容

这是一个公平的观点,“一定意味着QMutexLocker根本不可用”,但我确实错过了这一点。我想您指的是不太可能提出索赔的:

现在,当 PySide.QtCore.QMutexLocker对象被销毁(当函数 返回,因为locker是一个自动变量)


这不太可能,因为Python中没有
auto
变量存储类。我猜想,这将在进一步的调查中被证明是“让我们只需包装一个C++库,并假设范围语义工作”。如果这个猜测是正确的,您可能会使用来更好地保证可靠的解锁。

您没有正确使用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
在测试中,您可以在第一个示例中看到,锁返回stilllocked。在第二种情况下,当引发异常时,上下文管理器在离开函数之前释放锁

当使用C++时,我确信QutExExcLok会按照它的要求执行,只要范围结束,就可以解锁。但是在Python中,正如您所发现的,不应该依赖垃圾收集器来解锁。通过

with
语句的上下文管理器非常适合于此。你可以通过这种方式来告诉C++类的例子,它只是在函数顶部创建的。而python版本既有
\uuuuuuuuuuuuuuuu
方法,也有
\uuuuuuuuuuuuuuuu
方法

最后,使用
上下文可以将关键代码块包装在锁中,以限制需要放置的锁的数量,所以可以执行如下操作:

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

Thanx,我担心它是这样的,因为Python是GC-ed的。然而,正如我所提到的,这使得QMutexLocker的整个想法变得毫无价值,因为它的目的是不必担心解锁。当我没有抛出异常时,它似乎也起作用,这有点奇怪。关于不知道锁何时被删除,应该有同样的问题吗?我觉得这个答案有点笼统,绕过了正确的信息,只是做了一些假设。如果使用得当,QMutexLocker无疑是可用的。但我完全同意只锁定关键代码段以最小化锁。同意,我只是猜测,这就是为什么我赞成你的答案。我认为你的答案是关于你接触C++对象和PYQT包版本之间的不同的方式。还有垃圾收集与“自动”这显然是一个糟糕的答案。在
上下文之外使用
QMutexLocker
会使使用
QMutexLocker
的整个要点无效。如果您打算这样做,您最好使用更轻的
QMutex
。当然,你也不应该这样做;您应该在
上下文中使用
QMutexLocker
。当试图从引发的异常中恢复时,任何其他锁定模式都会引发竞争条件和死锁。很好,从来都不知道这是一个像with语句这样的好东西Py@Rolle:显然没有这里的另一个答案那么好,嗯?;-)那个人告诉你QMutexLocker不可靠。你的解释对我来说很有意义。有趣的是,即使PyQt代码也错误地使用了QMutexLocker:@jdg,至少这只是一个例子。但幸运的是,它们也没有在该函数体中提出自己的异常。只要没有引发意外的异常,并且调用方不希望访问异常处理程序中锁定的资源,它在技术上仍然可以正常工作。