スレッドに正常に終了するように指示しようとします。この目的のために、スレッドはすべての繰り返しで、スレッドが続行するか終了するかを示すグローバルブールフラグをチェックします。スレッドは次のように設定されています (コードはhttp://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/からのものです):
ImageFusionQt::ImageFusionQt(QWidget* parent)
: QMainWindow(parent)
{
captureThread = new QThread();
captureWorker = new CaptureWorker();
// Connects the threads started() signal to the process() slot in the worker, causing it to start.
connect(captureThread, SIGNAL(started()), captureWorker, SLOT(process()));
// Connect worker finished signal to trigger thread quit, then delete.
connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));
connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
// Make sure the thread object is deleted after execution has finished.
connect(captureThread, SIGNAL(finished()), captureThread, SLOT(deleteLater()));
// Give QThread ownership of Worker Object
captureWorker->moveToThread(captureThread);
captureThread->start();
}
CaptureWorker.cpp
void CaptureWorker::process()
{
while(true)
{
g_exit_lock->lockForRead();
if( g_exit )
{
g_exit_lock->unlock();
break;
}
g_exit_lock->unlock();
}
qDebug() << "CaptureWorker: Exiting.";
emit finished();
}
ここで、関数でフラグを true に設定してスレッドを停止しようとすると、process() メソッドは返されますが、スレッドは終了せず、wait() の呼び出しが永久にブロックされます。スレッドが終了しないのはなぜですか?
g_exit_lock->lockForWrite();
g_exit = true;
g_exit_lock->unlock();
QThread::sleep(15);
qDebug() << "ct finished? " << captureThread->isFinished();
captureThread->wait();
qDebug() << "All threads stopped.";
ログファイル出力:
2013.03.26 09:29:22[D] CaptureWorker: Exiting.
2013.03.26 09:29:37[D] ct finished? false
アップデート
私はいくつかのデバッグを行い、いくつかの興味深いものを見つけました:
- スレッドはイベント ループ (QEventLoop::exec) でブロックされます。明らかに受信していない quit() シグナルを待ちます。
- process() が戻った後、スレッドのイベントループが作成されます。私が行ったようにシグナルを接続することにより、スレッドの run() メソッドは、スレッドが作業を完了した後に呼び出されます (たとえば、process() が返されます)。
- イベント ループは、実際のループを実行する前に、ポストされたすべての終了イベントをクリアします。
私の結論
- イベントループが確立されるとquit()イベントが削除されるため、quit()スロットを接続しても機能しません
- スレッド オブジェクトで直接 quit() メンバー関数を呼び出すと、正常に終了するようです。これは、QThread::currentThread()->quit(); を使用して、外部または内部から実行できます。
未解決の質問
- イベントループが確立された後に process() メソッドを呼び出す方法はありますか?
- 作業が完了したときにイベントループが作成されるのは違和感があります。ただし、 QThread の使用方法はドキュメントに沿っています