Seite 1 von 1
[gelöst] QThread beenden mit aufräumen
Verfasst: 8. April 2011 16:33
von Willi2793
Hallo,
ich habe immer noch Probleme mit meinen QThreads. Ich definiere das ganze jetzt folgendermassen:
Code: Alles auswählen
QThread* thread = new QThread(this);
ConnectionTest* ct = new ConnectionTest();
ct->moveToThread(thread);
connect(thread, SIGNAL(started()) , ct , SLOT(startWork()));
connect(ct , SIGNAL(ended()) , ct , SLOT(deleteLater()));
connect(ct , SIGNAL(destroyed()) , thread, SLOT(quit()));
connect(thread, SIGNAL(finished()) , thread, SLOT(deleteLater()));
connect(thread, SIGNAL(terminated()) , thread, SLOT(deleteLater()));
thread->start();
Das Ganze läuft in einer Schleife recht oft ab. Es ist ja ein Streß-Test für eine Server-Anwendung.
Der Slot "startWork()" in ConnectionThread startet nun die Verarbeitung und wirft an deren Ende das "ended()" Signal aus. Das Aufräumen in dieser Klasse funktioniert auch und die Verbindung zum Server wird sauber abgebaut. Das "Ended()"-Signal soll dann die Ganzen oben verketten Aufräumarbeiten auslösen. Das scheint auch im Großen und Ganzen ganz gut zu funktionieren. Allerdings bekomme ich sporadisch die Meldung:
QThread: Destroyed while thread is still running
Und ich verstehe jetzt nicht warum. Ich rufe das deleteLater doch erst auf wenn der Thread fertig ist!?
Grüße,
Willi
Verfasst: 8. April 2011 16:55
von Christian81
Du löschst deinen Thread obwohl er noch in seiner Eventloop ist - was erwartest Du?
Siehe
http://doc.trolltech.com/4.7/qthread.html#run und
http://doc.trolltech.com/4.7/qthread.html#quit
Wenn ended() QThread::quit() aufrufen würde so wie es in der Doku steht... naja dann müsste es gehen.
Verfasst: 8. April 2011 18:49
von solarix
Ist
Code: Alles auswählen
connect(thread, SIGNAL(finished()) ,
thread, SLOT(deleteLater()),
Qt::QueuedConnection);
besser?
Verfasst: 8. April 2011 23:52
von Willi2793
Wieso lösche ich ihn wenn er noch in der Eventloop ist? Ich rufe das deleteLater doch auf wenn das finished()-Signal von ihm geworfen wurde. Danach ist seine Eventloop doch fertig? Wo habe ich denn da den Denkfehler? Das "quit()" vom thread wird ja schon vorher aufgerufen. Die Reihenfolge sollte sein:
ct wirft ended() -> ct->deleteLater()
ct wirft destroyed() -> thread->quit()
thread wirft finished() --> thread->deleteLater()
Da denke ich sollte der thread incl. Eventloop beendet sein wenn das deleteLater() aufgerufen wird!?
solarix hat geschrieben:Ist
Code: Alles auswählen
connect(thread, SIGNAL(finished()) ,
thread, SLOT(deleteLater()),
Qt::QueuedConnection);
besser?
Probiere ich morgen. Der Rechner mit QT ist jetzt nicht da

Aber danke für die Anregung. Werde berichten
Grüße,
Willi
Verfasst: 9. April 2011 15:49
von Willi2793
Nein, den Connectiontyp ändern bringt keine Veränderung. Schade.
Weitere Vorschläge?

Verfasst: 9. April 2011 18:31
von Christian81
Was erwartest Du denn noch
Code: Alles auswählen
connect(ct , SIGNAL(ended()) , ct , SLOT(deleteLater()));
Dein Thread sendet ended(), ist aber noch in der Eventloop da noch kein quit() aufgerufen wurde und Du löschst ihn...

Verfasst: 9. April 2011 19:36
von Willi2793
Christian81 hat geschrieben:Was erwartest Du denn noch
Code: Alles auswählen
connect(ct , SIGNAL(ended()) , ct , SLOT(deleteLater()));
Dein Thread sendet ended(), ist aber noch in der Eventloop da noch kein quit() aufgerufen wurde und Du löschst ihn...

Ah, da ist das Misverständnis. Ich gebe allerdings auch zu das ich nicht explizit darauf hingewiesen habe. "ct" ist eine von QObject abgeleitete Klasse und wird mit moveToThread einem QThread zugewiesen. Das Ende von ct wird mit dem ended() angezeigt. Danach wird ct aufgeräumt und wenn das aufgeräumt ist wird das Objekt von QThread (hier "thread") aufgeräumt. Deshalb ist das deleteLater() für ct kein löschen des QThread.
War es das was Du meintest?
Verfasst: 9. April 2011 20:08
von Christian81
Jetzt habe ich das Konstrukt kapiert...

Da bleibt wohl nur ein Breakpoint im Qt-Code an der Stelle an der die Warnung ausgegeben wird. Oder ein minimales Beispiel damit wir es auch mal testen können.
Verfasst: 9. April 2011 22:40
von Willi2793
So, ich habe dann mal Client und Server zusammen gestaucht. Der Server ist zwar immer noch etwas umfangreich, aber um den geht es auch nicht. Der Client macht mir das Kopfzerbrechen.
Vielen Dank für Eure Bemühungen.
In der GUI des Client einfach eine Zahl eingeben (ich teste immer mit 3) und dann auf den Button klicken. Es wird eine Verbindung zum Server hergestellt (localhost auf Port 36001) und 3mal Daten hin und her geschickt. Und das halt ständig bis der Client beendet wird (Close-Button des Window)
Verfasst: 10. April 2011 19:29
von Christian81
So... hat ein wenig gedauert aber ich habs gefunden

Es liegt an deinem Testcase - der Rest ist ok so (abgesehen vom fehlenden delete der ConnectionTest - Objekte)
Hier liegt das Problem:
Code: Alles auswählen
for(...
connect(this , SIGNAL(startThreads()) , thread, SLOT(start()));
}
emit startThreads();
Wenn ein Thread noch nicht gelöscht wurde, Du aber on_process_clicked() schon aufrufst bekommt der alte noch lebende Thread auch ein start() - Signal und wird noch einmal gestartet...

Ein 'disconnect(SIGNAL(startThreads()));' vor der for-Schleife oder gleich das connect komplett weglassen und start() direkt aufrufen und schon gehts.
Verfasst: 10. April 2011 22:25
von Willi2793
Christian81 hat geschrieben:So... hat ein wenig gedauert aber ich habs gefunden

Es liegt an deinem Testcase - der Rest ist ok so (abgesehen vom fehlenden delete der ConnectionTest - Objekte)
Das delete ist dem Abspecken zum Opfer gefallen. Im richtigen Programm ist es drin.
Christian81 hat geschrieben:Hier liegt das Problem:
Code: Alles auswählen
for(...
connect(this , SIGNAL(startThreads()) , thread, SLOT(start()));
}
emit startThreads();
Wenn ein Thread noch nicht gelöscht wurde, Du aber on_process_clicked() schon aufrufst bekommt der alte noch lebende Thread auch ein start() - Signal und wird noch einmal gestartet...

Ein 'disconnect(SIGNAL(startThreads()));' vor der for-Schleife oder gleich das connect komplett weglassen und start() direkt aufrufen und schon gehts.
So simpel und doch so kompliziert zu finden. Da hätte ich noch eine Weile (erfolglos) gesucht denke ich.
Super, vielen Dank
