1

スレッドに正常に終了するように指示しようとします。この目的のために、スレッドはすべての繰り返しで、スレッドが続行するか終了するかを示すグローバルブールフラグをチェックします。スレッドは次のように設定されています (コードは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 の使用方法はドキュメントに沿っています
4

2 に答える 2

2

ここで起こっていることはquit、まったく呼び出されていません。Qt には直接接続またはキュー接続があることがわかっています。これを使うと

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));

それは本当に自動接続タイプです。したがって、captureWorker を別のスレッドに移動したため、 Qt::QueuedConnectonが使用されます。はメインスレッドquit()で呼び出されます。しかし、あなたがしていることは、イベントループでキューに入れられたメインスレッドをブロックすることですが、スレッドが終了するのを待っているためブロックされています。 したがって、置き換えるように直接 quit() を呼び出したい場合がありますcaptureThread->wait();
quit()

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()), Qt::DirectConnection);

または、編集で提案したように quit() を直接呼び出すか、captureThread->wait();本当に必要な場合の代わりに、次のようなこともできます

  QEventLoop l;
  l.connect(captureThread, SIGNAL(finished()), SLOT(quit()));  
  l.exec(QEventLoop::ExcludeUserInputEvents);

または、スレッドの finished() シグナルに接続して、後でやりたいことを何でもできるcaptureThread->wait();ので、手動で待つ必要はまったくありません。
Qt にはさまざまな方法があります

于 2013-03-26T12:28:26.853 に答える
0

問題は、実際にメインスレッドとイベントループをブロックしているため、スレッドが終了シグナルを受信できないことです。この問題は、次のようにすることで修正されます。

g_exit_lock->lockForWrite();
g_exit = true;
g_exit_lock->unlock();

QThread::sleep(15);
qDebug() << "ct finished? " << captureThread->isFinished();

// You are missing below line, without this, main thread will block
captureThread->quit();
captureThread->wait();

qDebug() << "All threads stopped.";
于 2015-09-23T12:57:01.020 に答える