2

QThreadから直接継承するのではなく、workerオブジェクトを使用してmoveToThreadでスレッドに移動する必要があることを読んでいます。しかし、オブジェクト ワーカーでループを停止する方法が見つかりません。たとえば、テストループがあります:

void CollectionWorker::doWork()
{
    for (int i = 0; i < 10; ++i) {
        sleep(1);
        emit ping(i);
    }
}

今、私はこのオブジェクトをスレッドに移動しています:

worker->moveToThread(mTh); 

これはうまくいっています。しかし、mTh.quit() を呼び出すと、スレッドは doWork のループが終了するまで待機しています。QThread から直接継承すると、各ループでスレッドのステータスを確認し、スレッドが終了したときにループを中断できますが、ワーカー オブジェクトでそれを行う方法がわかりません。ワーカー オブジェクトにフラグを作成して、メイン スレッドから切り替えることはできますか? または、スレッドの所有者を見つけてステータスを確認できますか? または、スレッドを開始する前に、ワーカー オブジェクトにスレッド ポインタを設定してから、ステータスを確認することをお勧めします。最適なスレッド セーフ ソリューションは何ですか?

よろしく

4

4 に答える 4

7

スレッド オブジェクトで quit() または exit() を呼び出すと、実行中のスレッドがある場合、スレッドのイベント ループが終了します。しかし、あなたが正しく指摘したように、元の問題は同じままです。ワーカー関数がイベント ループによって既に実行されており、forever 構造を持つ長時間実行される関数である場合はどうなりますか。quit() または exit() の呼び出しは、ワーカー関数が戻るまで単に待機します。

内部フラグを変更するパブリック関数を呼び出し元が使用できるようにする以外に、いくつかのアプローチを提案できます。

  • ワーカー クラスに終了シグナルとスロットを与えます。以下のようなもの。

    signals:
        void signalTermination();
    public slots:
        void setTerminationFlag();
    private:
        QMutex mutex;
        bool terminationRequested;

あなたのスロットは何かのように見えます。

void setTerminationFlag()
{
    QMutexLocker locker(&mutex);
    terminationRequested = true;
}

次に、永久ループの繰り返しごとに doWork 関数の変数を確認できます。

mutex.lock();
if(terminationRequested)
{
    //break from loop and effectively doWork function
}
mutex.unlock();

単純なメンバー関数の代わりにシグナルとスロットを使用する理由の 1 つは、ワーカー関数が同期されたコード ブロック内で実行時間の長いタスクを実行している場合、パブリック関数は同期オブジェクトにアクセスするまでブロックされたままになるためです。これは、パブリック終了メソッドの呼び出しスレッドが UI スレッドである場合に悪影響を与える可能性があります。

  • Qt 5.2以降を使用している場合の別のクリーンでシンプルなアプローチ

QThread の requestInterruption() メソッドを使用します。このメソッドは、doWork() 関数で isInterruptionRequested() 関数呼び出しを介して確認できるスレッド オブジェクトにアドバイザリ フラグを設定します。QThread::isInterruptionRequestedドキュメントに記載されている次のコード スニペットを参照してください。

void long_task() {
    forever {
        if ( QThread::currentThread()->isInterruptionRequested() ) {
            return;
        }
    }
}

ここで直接 quit() を呼び出して、スレッドのイベント ループを終了することもできます。

于 2015-06-20T22:28:48.747 に答える
3

編集:申し訳ありませんが、あなたの質問を誤解しました。

いくつかの選択肢があります。いくつかのフラグを作成し、処理ループの各反復の前に、フラグが設定されているかどうかを確認できます。または、リスト/キューでデータを処理している場合は、特別なデータの終わり要素でプロセスを終了するように通知できます。

于 2013-03-07T11:05:50.927 に答える
0

Qt でワーカー スレッドを破棄する慣用的な方法は、シグナル/スロット インターフェイスを使用することです。

 CollectionWorker *worker = new CollectionWorker;
 QThread *workerThread = new QThread(this);

 connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()));
 connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
 worker->moveToThread(workerThread);

これを機能させるには、CollectionWorker が QObject クラスから継承し、Q_OBJECT マクロを宣言する必要があります。

于 2013-03-08T21:09:36.197 に答える