我在 Windows 7 上的 Qt 中需要一些帮助。似乎 QtreadyRead()
信号是由异步过程调用发出的,这会导致代码在同一个线程中并发执行。
在我的示例中,我有一个队列,该队列应该由锁访问,DoRead()
并且可以在其中访问。DoTimer()
整个操作在 ui (main) thread中运行。但是有时会DoRead()
发生所谓的死锁。代码在 中停止执行DoRead()
。如果显示消息框并因此DoTimer()
停止执行,则死锁是可重现的。但是我很惊讶地看到它OnRead()
仍然被并发调用。对我来说唯一的解释是,这OnRead()
是由 Windows APC 调用的。
请参阅 MSDN 文章异步过程调用:
异步过程调用 (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);
}
如果没有对队列的并发访问(没有多线程),则不需要锁。