Windows 7 の Qt で支援が必要です。readyRead()
非同期プロシージャ呼び出しによって Qt シグナルが発行され、コードが同時に実行されますが、同じスレッドで実行されるようです。
私の例では、ロックによってアクセスされ、DoRead()
アクセスされるキューがあります。DoTimer()
操作全体が ui (メイン) スレッドで実行されています。しかし、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);
}
キューへの同時アクセスがない (マルチスレッドでない) 場合、ロックは必要ありません。