QThread не останавливается / не обрабатывает сигнал - PullRequest
3 голосов
/ 15 сентября 2011

Я пытаюсь выполнить некоторую работу в отдельном потоке и остановить этот поток, когда работа будет завершена.

Я установил соединение вот так

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

но слот quit () никогда не вызывается, когда я посылаю сигнал Finished (). Командная строка не показывает никаких предупреждений, связанных с ошибочными соединениями.

Я создал простой тестовый проект, чтобы сузить проблему, и у меня такое же поведение:

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. testClass имеет названный слот doWork().
  3. Когда TestClass::doWork() завершено, выдается сигнал finished().
  4. Цикл событий testThread получает сигнал и перенаправляет его в quit() слот
  5. testThread.wait() возвращает ожидание после завершения потока.

Шаги 1-3 работают, и я получаю вывод qDebug(). Проблема на шаге 4: сигнал запускается и пересылается в какой-то цикл обработки событий (я немного отлаживал его, но не смог выяснить, в какой цикл обработки он был запущен), но слот quit() никогда не вызывается.

Что я делаю не так?

P.S .: Пожалуйста, не предлагайте вместо этого создавать подклассы QThread, весь смысл того, что я пробую этот выход, заключается в том, что я хочу избежать создания подклассов QThread.

Ответы [ 2 ]

5 голосов
/ 15 сентября 2011

Я считаю, что проблема в том, что у вас на самом деле нет цикла событий Qt, запущенного в сценарии.Если вы замените testThread.wait() на a.exec() (который запускает цикл событий Qt), вы должны увидеть, что ваши сигналы / слоты обрабатываются должным образом.

Если вы хотите, чтобы приложение завершало работу после завершения потока, вы можете использоватьСлот QCoreApplication quit() для этого.

1 голос
/ 19 ноября 2013

У меня была такая же проблема, и я нашел ответ.Вот мой вопрос: Для чего нужна функция QThread.wait ()?

Чтобы решить вашу проблему, вам не нужно запускать a.exec (), что вамнужно вместо того, чтобы вызывать quit (), который пытается отправить сигнал в цикл событий вашего приложения (которого, очевидно, не существует), вы должны вызывать его напрямую.

Так что для вашего кода,Отбросьте строку:

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

И вместо:

emit finished();

Используйте:

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

Тада ... проблема решена.Извлеченный урок: не пытайтесь выйти из рабочего потока с помощью механизма qt signal-slot изнутри него, потому что ваши сигналы не попадают туда, где они должны (цикл обработки событий вашего рабочего потока), но они в конечном итоге создаютнить вместо.Вы никогда не знаете, что делает этот поток, и работает ли его цикл обработки событий, и это не должно быть полезным для вашего рабочего потока в любом случае ... Вместо этого вызывайте quit напрямую.

...