我需要在Windows 7中使用Qt的一些帮助。似乎Qt的
readyRead() 信号是由异步过程调用发出的,这会导致代码在相同的线程中并发执行。
例如,我有一个队列,应该由 DoRead()
和在锁定下访问的 DoTimer()
访问,整个操作在 UI(主)线程中运行。但是,有时会发生死锁,因为调用 DoRead()
。代码将停止在 DoRead()
处执行。如果显示消息框,则可以复制死锁。但是,我惊讶地发现, OnRead()
仍然是同时调用的。对我来说唯一的解释是, OnRead()
由Windows APC调用。
请参阅MSDN文章 Asynchronus Procedure Calls :
异步过程调用(APC)是在特定线程的上下文中异步执行的函数。当将APC排队到线程时,系统会发出软件中断。 线程下次调度时,它将运行APC函数。
我的假设是 readyRead()
可能是一个APC,这是正确的吗?
在任一情况下,我该怎么做才能防止死锁?我需要在 DoRead()
中访问队列以填充队列,并在 DoTimer()
(当然还有其他方法)中读取、写入或删除来自同一队列的条目。递归互斥锁不是解决方案,因为两个调用都发生在同一线程中。
class QMySocket : public QTcpSocket {
public:
QMySocket() {
...
connect(this, SIGNAL(readyRead()), this, SLOT(DoRead()));
connect(_MyTimer, SIGNAL(timeout()), this, SLOT(DoTimer()));
...
}
private:
QTimer* _MyTimer;
QQueue<int> _MyQueue;
QMutex _Lock;
void DoRead() {
_Lock.lock(); // <-- Dead Lock here (same Thread ID as in DoTimer)
_MyQueue... // Do some queue operation
// DoSomething
_Lock.unlock();
}
void DoTimer() {
_Lock.lock();
QQueue<int>::iterator i = _MyQueue.begin();
while (i != _MyQueue.end()) { // Begin queue operation
if (Condition) {
QMessageBox::critical(...);
i = _MyQueue.erase(i);
} else {
i++;
}
} // end queue operation
_Lock.unlock();
}
};
编辑2:我发现这与APC无关。问题只是由QMessageBox创建的额外消息循环。
不要直接调用QMessageBox,所有消息将被排队,并在任何队列操作后显示。
void DoTimer() {
QList<QString> Messages;
QQueue<int>::iterator i = _MyQueue.begin();
while (i != _MyQueue.end()) { // Begin queue operation
if (Condition) {
Messages.append(...);
i = _MyQueue.erase(i);
} else {
i++;
}
} // end queue operation
QMessageBox::critical(Messages);
}
如果队列没有并发访问(没有多线程),则不需要锁定。