Qt 无法获取QMutex上的锁
我目前正在开发的应用程序是多线程的,线程之间共享大量资源。我使用qmutex是为了保护共享资源,尽管在实践中,试图同时锁定同一互斥锁的不同线程之间很少会发生争用 尽管如此,我还是发现我的应用程序频繁地陷入停顿。当我中断执行并检查发生了什么时,我发现一个线程被暂停,因为它无法获得所需的互斥锁 我已经检查过互斥锁总是从同一线程锁定和解锁的——事实上,几乎总是在同一个花括号块中——在我的最新一轮故障排除中,我用定义如下的“nMutex”对象替换了所有裸露的QMUTEX:Qt 无法获取QMutex上的锁,qt,qmutex,Qt,Qmutex,我目前正在开发的应用程序是多线程的,线程之间共享大量资源。我使用qmutex是为了保护共享资源,尽管在实践中,试图同时锁定同一互斥锁的不同线程之间很少会发生争用 尽管如此,我还是发现我的应用程序频繁地陷入停顿。当我中断执行并检查发生了什么时,我发现一个线程被暂停,因为它无法获得所需的互斥锁 我已经检查过互斥锁总是从同一线程锁定和解锁的——事实上,几乎总是在同一个花括号块中——在我的最新一轮故障排除中,我用定义如下的“nMutex”对象替换了所有裸露的QMUTEX: class nMutex :
class nMutex : public QMutex
{
public:
nMutex() : QMutex(),
locks(0),
{}
void lock(const char * callingFilename, int callingLineNo)
{
// QMutex::lock(); // Frequently hangs, so tried the following instead...
if (!tryLock(1000))
{
printf("Cannot obtain mutex at line %d of %s; locks = %d",
callingLineNo, callingFilename, locks);
}
else
{
if (isRecursive())
++locks;
else
locks = 1;
}
}
bool tryLock(int timeout = 0) // Hides rather than overrides QMutex's tryLock,
// which is not virtual
{
bool result = QMutex::tryLock(timeout);
if (result)
{
if (isRecursive())
++locks;
else
locks = 1;
}
return result;
}
bool isLocked() const { return (locks > 0); }
int lockDepth() const { return locks; }
void unlock()
{
if (!locks) return;
QMutex::unlock();
if (isRecursive())
--locks;
else
locks = 0;
}
private:
int locks;
};
…并将我对mutex.lock()的所有调用替换为
我发现这经常失败,当它失败时,它总是报告“locks=0”-换句话说,没有其他线程已经有互斥锁了,但是试图获取互斥锁的线程却无法获取互斥锁。失败似乎是随机发生的,无论在我的代码中调用mutex.lock()的位置如何
目前我可以看到两种可能性:
(1) 我很愚蠢,没有发现上述方法有什么问题,或者
(2) QMutex中有一个bug。这似乎不太可能,因为我没有看到任何报告,我已经在Qt5.3和5.4的至少三个版本(包括最新的5.4.1)中尝试过
有没有办法测试这两种可能性中哪一种最有可能是正确的?例如,在无法获取互斥锁的情况下,是否有办法找出具体原因?您的上述方法至少有一个缺陷:
类中的locks
字段在不同线程的lock()和unlock()之间不同步,其值可能错误。无论如何,互斥体是非常基本的生物,我简直不敢相信QMutex中有bug。我通常只是通过仔细分析所有线程的调用堆栈来调试这些问题:必须有某个互斥锁以前被锁定但尚未解锁的地方。我不确定我是否看到了这一点,因为locks变量只有在底层QMutex被锁定或解锁后才被更新。无论如何,我发现了另一个可能是关键的问题。由于QMutex::lock()不是虚拟的,因此形式为QMutexLocker locker(&myNMutex)的指令通过传递我仔细的引用计数机制来调用QMutex::lock(),而不是nMutex::lock()!在我的代码中,我混合了QMutexLockers和manual lock()-unlock()对。我已经进行了重构,将QMutexLockers与qmutex一起使用,现在看来一切正常。
mutex.lock(__FILE__, __LINE__).