QThread выдает сигнал finish(), но isRunning() возвращает true, а isFinished() возвращает false

Ниже приведен код моей реализации qthread. Я пытаюсь получить данные GPS со спутника. QThread не выдает сигнал finish(), даже когда программа выходит из функции слота gpsSearch(). Функция locateMe() вызывается всякий раз, когда нажимается кнопка. В первый раз, когда поток не запущен и нажата кнопка, он печатает истинное значение для функции isRunning() и печатает ложное значение для функции isFinished(). Мне пришлось вызвать функцию quit() QTherad, чтобы вручную остановить поток. После этого он переходит к подключенной функции threadQuit() в классе gnssProvider. Но даже после этого, если я нажму кнопку, она выведет истинное значение для isRunning и ложное для isFinished() в функции locateMe().

GPSInfo::GPSInfo()
{
    hybridGPSFound = satelliteGPSFound = networkGPSFound = false;
    qDebug()<<"Thread Creating";
    gnssThread = new QThread;
    gnssProvider = new LocationFetcher(this,GEOLOCATION_PROVIDER_GNSS,1);
    gnssProvider->moveToThread(gnssThread);
    connect(gnssThread, SIGNAL(started()), gnssProvider, SLOT(gpsSearch()));
    connect(gnssThread, SIGNAL(finished()), gnssProvider, SLOT(threadQuit()));
}
void LocationFetcher::gpsSearch()
{
    if (BPS_SUCCESS != geolocation_request_events(0))
    {
       fprintf(stderr, "Error requesting geolocation events: %s", strerror(errno));
       return;
    }
    geolocation_set_provider(GPS_Search_Provider);
    geolocation_set_period(GPS_Search_Period);
    while (!stopThread)
    {
        bps_event_t *event = NULL;
        bps_get_event(&event, -1);

        if (event)
        {
            if (bps_event_get_domain(event) == geolocation_get_domain() && bps_event_get_code(event) == GEOLOCATION_INFO)
            {
                handle_geolocation_response(event);
                break;
            }
        }
    }
    geolocation_stop_events(0);

    this->quit();

}
void GPSInfo::LocateMe()
{
    qDebug()<<"Thread Running: "<<gnssThread->isFinished();
    qDebug()<<"Thread Running: "<<gnssThread->isRunning();

    gnssThread->start();
    hybridThread->start();
    networkThread->start();

 }

person Tahlil    schedule 11.06.2013    source источник
comment
Вы уверены, что не перепутали isFinished и isRunning? У вас есть "Thread Running: " в обеих строках.   -  person Pavel Strakhov    schedule 11.06.2013
comment
Нет, не делал :) Мне было лень это исправлять :P   -  person Tahlil    schedule 11.06.2013
comment
Вы можете опубликовать полный пример? Может ветка не закончилась   -  person BЈовић    schedule 13.06.2013
comment
Я бы предложил попытаться сократить код до минимального примера, который компилируется, но все же показывает проблему. Это поможет вам точно определить, в чем проблема, а нам предоставить ответ (поскольку потоки могут быть сложными, и полезно видеть, где и когда вы вызываете функции).   -  person Boris Dalstein    schedule 14.06.2013
comment
В чем вопрос, собственно?   -  person Phlucious    schedule 17.06.2013


Ответы (3)


Жизненный цикл QThread работает следующим образом:

  1. Вы звоните QThread::start().
  2. В этот момент isRunning() должен начать возвращать true.
  3. Внутренности резьбы начинаются. Они излучают сигнал started().
  4. Внутренности потока вызывают run().
  5. Если вы не переопределите это в подклассе, run() вызывает exec().
  6. exec() входит в цикл обработки событий и остается там до тех пор, пока не будет вызван quit() или exit().
  7. exec() и run() возвращаются к внутренностям.
  8. В этот момент isFinished() должно начать возвращать true и isRunning() false.
  9. Внутренности излучают сигнал finished().
  10. Внутренности делают некоторые последние очистки.
  11. Поток завершается по-настоящему.

Таким образом, вам нужно вызвать quit() после того, как ваш сборщик местоположения будет выполнен, но this->quit() не вызывает quit() в потоке! Вероятно, поэтому он ничего не делает.

Ваш код выглядит так, как будто он был создан по образцу этой статьи:

http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

Обратите внимание, как она подает своему рабочему сигнал finished() (не такой, как QThread::finished) и подключает его к слоту QThread::quit().

person Sebastian Redl    schedule 13.06.2013
comment
Этот пост является правильным ответом. Я бы только добавил, что нам нужно больше узнать о слоте threadQuit, чтобы сказать больше. Если этот слот удаляет поток, мне кажется, что у вас может быть оборванный указатель. - person Phlucious; 17.06.2013
comment
Большое спасибо, что дает мне лучшее понимание QThread :) - person Tahlil; 19.06.2013
comment
Очень исчерпывающий ответ, который трудно найти в другом месте. - person Trilarion; 10.04.2014

Предполагается, что поток не завершится, пока вы не завершите его вручную. Объект потока содержит цикл событий, поэтому он не завершится, пока цикл событий не завершится, как объяснил Себастьян.

Короче говоря, ваши соединения сигнал-слот концептуально обратные - объект должен завершать поток, когда он закончит делать свою работу, а не наоборот.

person Phlucious    schedule 17.06.2013

Какую версию Qt вы используете?

Qt 4.8 возвращал неверные значения до версии 4.8.4 (ошибка Qt 30251). Эта ошибка была исправлена ​​в версии 4.8.5.

person Frank    schedule 19.04.2017