Мне нужна некоторая помощь в Qt в Windows 7. Похоже, что сигнал Qt readyRead()
испускается асинхронным вызовом процедуры, который приводит к тому, что код выполняется одновременно, но в том же потоке .
В моем примере у меня есть очередь, к которой должен обращаться DoRead()
, а в DoTimer()
, к которой обращается блокировка.Вся операция выполняется в пользовательском (основном) потоке .Однако иногда, когда DoRead()
называется, возникла мертвая блокировка.Код останавливает выполнение в DoRead()
.Мертвая блокировка может быть воспроизведена, если отображается окно сообщения и выполнение DoTimer()
останавливается.Однако я был удивлен, увидев, что OnRead()
все еще вызывается одновременно.Единственное объяснение для меня заключается в том, что OnRead()
вызывается APC Windows.
См. Статью 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();
}
};
Edit 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);
}
Блокировки не требуются, если естьнет одновременного доступа к очереди (нет многопоточности).