2013-06-11 16 views
9

Poniżej znajduje się kod implementacji qthread. Próbuję uzyskać dane GPS z satelity. QThread nie generuje sygnału finished() nawet wtedy, gdy programy opuszczają funkcję automatu do wstawiania gpsSearch(). Funkcja locateMe() jest wywoływana po kliknięciu przycisku. Za pierwszym razem, gdy wątek nie zostanie uruchomiony, a przycisk zostanie kliknięty, drukuje on prawdziwą wartość dla funkcji isRunning() i wypisuje fałszywą wartość dla funkcji isFinished(). Musiałem zadzwonić do funkcji QTherad quit(), aby ręcznie zatrzymać wątek. Następnie przechodzi do połączonej funkcji threadQuit() w klasie gnssProvider. Ale nawet po tym, gdy kliknę przycisk, wypisze on true value dla isRunning i false dla isFinished() w funkcji locateMe().QThread emituje gotowy() sygnał, ale funkcja isRunning() zwraca wartość true, a isFinished() zwraca wartość false

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(); 

} 
+3

Czy jesteś pewien, że nie pomieszałeś isFinished i isRunning? W obu liniach mamy '' Thread Running: "'. –

+0

Nie, nie zrobiłem :) Byłem zbyt leniwy, aby to naprawić: P – Tahlil

+1

czy możesz zamieścić pełny przykład? Może wątek nie zakończył się. –

Odpowiedz

27

Sposób cykl życia QThread działa to tak:

  1. zadzwonić QThread::start().
  2. W tym momencie isRunning() powinien rozpocząć zwracanie wartości true.
  3. Początek wątków. Emitują sygnał started().
  4. Wewnętrzny wątek wywołania run().
  5. Jeśli nie zastąpisz tego w podklasie, run() dzwoni exec().
  6. exec() wchodzi w pętlę zdarzeń i pozostaje tam do momentu wywołania quit() lub exit().
  7. exec() i run() powrót do elementów wewnętrznych.
  8. W tym momencie isFinished() powinien rozpocząć zwracanie wartości true i isRunning() fałsz.
  9. Wnętrza emitują sygnał finished().
  10. Elementy wewnętrzne wykonują końcowe czyszczenie.
  11. Wątek kończy się na prawdziwy.

Więc trzeba zadzwonić quit() po lokalizacji fetcher odbywa się - ale this->quit() nie dzwoni quit() na wątku! Pewnie dlatego nic nie robi.

Twój kod wygląda trochę jak to było wzorowane tego artykułu:

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

Uwaga jak ona daje jej pracownik jest finished() sygnał (to nie to samo QThread::finished) i łączy go do gniazda QThread::quit().

+0

Ten post jest prawidłową odpowiedzią. Dodam tylko, że musimy wiedzieć więcej o wątku threadQuit, by powiedzieć więcej. Jeśli ten slot usuwa wątek, wydaje mi się, że możesz mieć zwisający wskaźnik. – Phlucious

+0

Wielkie dzięki, które daje mi lepsze zrozumienie QThread :) – Tahlil

+0

Bardzo wyczerpująca odpowiedź, trudna do znalezienia gdzie indziej. – Trilarion

1

Jest zamierzone zachowanie, że wątek nie zostanie zamknięty, dopóki nie zakończysz go ręcznie. Obiekt wątku obsługuje pętlę zdarzeń, więc nie kończy się, dopóki pętla zdarzeń nie zostanie zamknięta, jak wyjaśnił Sebastian.

Krótko mówiąc, twoje połączenia z gniazdami sygnałowymi są konceptualne wstecz - obiekt powinien zakończyć wątek po zakończeniu wykonywania swojej rzeczy, a nie odwrotnie.

0

Którą wersję Qt używasz?

Qt 4.8 zwrócił błędne wartości do 4.8.4 (błąd Qt 30251). Ten błąd został naprawiony w wersji 4.8.5.

Powiązane problemy