项目中出现一个问题,当使用QMessageBox弹窗后,通讯线程卡住,run()函数中的while(true)循环一直未进入。
这个现象首先猜测弹窗会卡住界面,但是经过添加打印信息,发现主线程中的QTimer定时器仍在正常执行,但是通讯线程while循环中的打印信息却一直未打印,为什么主线程没有卡住,但子线程卡住了,一下子懵了,居然会有这么神奇的事情。
最终通过代码回退对比,发现问题原因竟然出现在QMutexLocker上。
QMutexLocker上锁和解锁的原理:在该局部变量被创建的时候上锁,当所在函数运行完毕后该QMutexLocker局部变量在栈中销毁掉,也就相对应的解锁了
下面展示一些 代码,Controller为通讯线程类。
void Controller::slotReadConfirmed(const QByteArray &data)
{
QMutexLocker locker(&readMutex);
// check hash table to decide where to send the received data.
BaseClientWidget *clientUI = nullptr;
if(m_ui_hash.contains(m_current_ui)){
clientUI = m_ui_hash.value(m_current_ui);
m_readNextPackage = true; // break the reading block after handle data. do not modify m_current_ui before you read the current ui.
if(data.isEmpty()){
qDebug() << "Controller:: recv data length = 0";
return;
}
clientUI->handleData(data);
}else{
m_readNextPackage = true; // doesn't contains current ui
}
}
QMutexLocker 的作用域是{}内部,所以slotReadConfirmed()函数中对handleData()也进行了加锁,执行虚函数handleData时并没有解锁,而handledata是在窗口类中执行的,而弹窗刚好是在handledata中弹出,所以handledata阻塞,那么slotReadConfirmed也被阻塞,即通讯线程被阻塞,所以run函数中的while(true)循环不再进入。
解决方案:不适用QMutexlocker,使用lock()和unlock()函数即可