3

別のスレッドでいくつかの作業を実行し、作業が完了したらそのスレッドを停止しようとしています。

このような接続を設定しました

thread.connect( workerClass, SIGNAL( finished() ), SLOT( quit() ) );

しかし、終了した()シグナルを発したときに、quit()スロットが呼び出されることはありません。コマンド ラインには、失敗した接続に関連する警告は表示されません。

問題を絞り込むために簡単なテスト プロジェクトを作成しましたが、同じ動作が得られます。

TestClass.h:

#ifndef TESTCLASS_H
#define TESTCLASS_H
class TestClass : public QObject
{
    Q_OBJECT
public:
    TestClass() { }
signals:
    void finished();
public slots:
    void doWork();
}
#endif // TESTCLASS_H

TestClass.cpp:

#include "TestClass.h"
#include <QtCore/QDebug>
void TestClass::doWork()
{
    qDebug() << "Starting";
    for( long i = 0; i < 1000000000; i++ );
    qDebug() << "Done";
    emit finished();
};

そしてmain.cpp:

#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include "TestClass.h"

int main( int argc, char* argv[] )
{
    QCoreApplication a( argc, argv );

    TestClass testClass;
    QThread testThread;

    testClass.moveToThread( &testThread );

    testThread.connect( &testClass, SIGNAL( finished() ), SLOT( quit() ) );
    testClass.connect( &testThread, SIGNAL( started() ), SLOT( doWork() ) );

    testThread.start();
    testThread.wait();

    return 0;
}

だからここに私が起こると予想したものがあります:

  1. 処理が完了testThread.start()すると、スレッドのrun()関数が呼び出され、内部的exec()にイベント ループが呼び出されて開始されます。さらに、シグナルをスローしstarted()ます。
  2. testClassdoWork()と呼ばれるスロットを持っています。
  3. 完了すると、シグナルTestClass::doWork()がスローされます。finished()
  4. のイベントループはtestThreadシグナルを受信し、それをそのquit()スロットに転送します
  5. testThread.wait()スレッドが終了したため、待機から戻ります。

ステップ 1 ~ 3 が機能し、qDebug()出力が得られます。問題はステップ 4 にあります: シグナルが発生し、いくつかのイベント ループに転送されます (少しデバッグしましたが、どのイベント ループに発生したのかわかりませんでした) が、quit()スロットは呼び出されません。

私は何を間違っていますか?

PS: 代わりに QThread をサブクラス化することを提案しないでください。私がこの方法を試しているのは、QThread のサブクラス化を避けたいからです。

4

2 に答える 2

5

問題は、シナリオで実際に Qt イベント ループが実行されていないことだと思います。(Qt イベント ループを開始する)に置き換えるtestThread.wait()a.exec()、シグナル/スロットが適切に処理されていることがわかります。

スレッドが終了したときにアプリケーションを終了させたい場合は、QCoreApplication のquit()スロットを使用して終了させることができます。

于 2011-09-15T15:06:51.343 に答える
1

私は同じ問題を抱えていて、答えを見つけました。ここに私の質問があります: QThread.wait() 関数の使用は何ですか?

問題を解決するには、a.exec() を実行する必要はありません。アプリケーションのイベント ループにシグナルを送信しようとする quit() を呼び出す代わりに、a.exec() を実行する必要があります (これは明らかに送信されません)。存在する)、直接呼び出す必要があります。

したがって、コードでは、次の行を削除します。

testThread.connect( &testClass, SIGNAL( finished() ), SLOT( quit() ) );

そして代わりに:

emit finished();

使用する:

this->thread()->quit();

多田...問題は解決しました。学んだ教訓: ワーカー スレッド内から qt シグナル スロット メカニズムによって終了しようとしないでください。これは、シグナルが本来あるべき場所 (ワーカー スレッドのイベント ループ) で終わらないためです。代わりにスレッド。そのスレッドが何をしているのか、そのイベントループが実行されているかどうかはわかりません。とにかく、これはワーカースレッドには関係ありません...代わりに、終了を直接呼び出します。

于 2013-11-19T19:40:11.257 に答える