C++ QT-GUI durch Workerthreads triggern

T_55

Lieutenant
Registriert
Feb. 2013
Beiträge
638
Hallo,

bin gerade am GUI bauen per QT und scheinbar ist es leider so, dass man mit der QT GUI ausschließlich im GUI Thread arbeiten darf (MainWindow).
Jetzt habe ich ein Programm wo hin und wieder verschiedene Worker-Threads was in der GUI anzeigen sollen.
Das Problem ist, sobald ich zB per condition-Variable im MainWindow-Thread blockierendes Warten einbaue um Signale und Daten von den Threads zum empfangen und anzuzeigen dann blockiere ich die ganze GUI.
Wenn man um dies zu lösen dann ein Thread erzeugt zB std::thread thr(&MainWindow::showData,this); in dem man eigentlich die GUI-Funktionalitäten hätte, dann wirft es zur Laufzeit den Fehler "QObject: Cannot create chlidren for parent that is in a different thread. Schade.
Ohne GUI hätte ich keine Probleme per condition variable, Threads, locks alles schön zu machen, aber ich habe keine Ahnung wo ich blockierendes Warten reinbekomme ohne das GUI einzufrieren. Zwischendurch will ich noch die Knöpfe bedienen können.
Gibt es in QT eine Funktion die blockierendes Warten zulässt ohne dabei die GUI einzufrieren? Die Knöpfe sind doch am Ende auch nichts anderes als blockierendes Warten, müsste doch auch ausgelöst durch Threads gehen...?
Gerne würde ich auch vermeiden in meine "reinen" C++Threads zuviel QT-spezifische Dinge reinzubauen.

Grüße
 
Kenne das Problem, ich habe es durch Signal und Slot gelöst. Machst nen emit ( data ) und dann nen Slot und auswertung
 
Danke erstmal. Hab jetzt ewig viel angeschaut, Lesezeichen ohne Ende und jetzt etwas verwirrt. Scheinbar muss man für die Signal Dinge dann in jedem Fall alles von std::threads auf QThreads umschreiben was ich vermeiden wollte. Es gibt wohl auch was per invokeMethod und std::function https://stackoverflow.com/questions/49510026/updating-qt-gui-from-a-different-stdthread sieht nach Abenteuer aus zumindest für mich ;)

Ich glaube ich mache jetzt erstmal ein QTimer der dann zb alle x Millisekunden in einem atomic bool als Signal schaut ob die Threads Daten zum anzeigen bereit gelegt haben. Ist zwar nicht so richtig Realtime und mehr Overhead als bei einer condition variable aber effektiver als jetzt eine Woche mich in den Tiefen von QT rumzuschlagen und mein ganzes Threading umzuschreiben...
 
Zuletzt bearbeitet:
Als Leser gehen bei mir zunaechst mal die Alarmleuchten an, wenn du sagst, dass du Worker-Threads etwas in der GUI anzeigen lassen moechtest. Prinzipipell sollten deine Worker-Threads dein Datenmodell fuettern. Die GUI schliesslich zeigt den Inhalt deines Datenmodells an. Worker-Threads direkt etwas in die GUI schieben zu lassen, riecht erstmal nach schlechter Architektur.
 
Ja so ist es auch gedacht, die Worker füttern eine Daten-Klasse mit Daten und signalisieren dann der GUI das dort nun neue Daten liegen. Daraufhin zeigt GUI das an. Die Datenklasse ist für alle zugänglich und natürlich gelockt wenn ein thread zugreift.
Das eigentliche Problem ist der GUI aus einem std::thread ein Signal zu geben ohne überall QT-spezifische Dinge reinzunehmen (was mir ja wichtig ist).
Das mit QTimer, wie zuvor beschrieben, ist nicht so wirklich befriedigend, daher habe ich jetzt folgendes Konzept im Auge:

GUI startet zu Beginn ein einzigen QThread der eine Signal-Verbindung zur GUI hat und dort die Funktion triggern kann welche Graphen aktualisiert/anzeigt.
Im QThread ist eine while(1) Schleife die blockierend per condition_variable auf Signale von den Threads wartet.

Also eine Anzeigeaktion wäre dann so:
1. blockierendes Warten im QThread per condition-variable.
2. Einer der Threads hat neue Daten fertig und
- lockt die Datenklasse
- schreibt in Datenklasse die Daten rein
- benachrichtigt per condition_variable den QThread
- Lock bleibt erhalten...
3. QThread erhält Signal per condition_variable und gibt Signal per QT-Signal an GUI weiter um dort Anzeigefunktion zu starten.
4. GUI-Funktion in MainWindow wird ausgeführt und liest Daten aus Datenklasse und zeigt Daten an.
Erst jetzt wird der Lock der Datenklasse wieder freigegeben.

So trenne ich den reinen C++ Code von QT-spezifischen Code und schaffe über den QThread eine Trigger-Schnittstelle.
Durch den kleinen Umweg hab ich zwar immer zwei Signale (Thread zu QThread und QThread zu GUI) aber kann die Threads völlig im reinen C++ halten was mir wichtig ist weil ich dann die Codes ohne QT/GUI auch in Konsole etc nutzen kann.

Soweit erstmal, in die Signal-Sachen von QThread zu GUI(MainWindow) muss ich mich noch reinarbeiten, das ist noch das einzige Hindernis.

Grüße
 
Benutzt du Qt's Model/View Abstraktion? Wenn ja, solltest du aus deinem Model deine threads starten können und wenn diese fertig sind die Daten setzen können und so ein GUI update triggern können.

Du musst zwar etwas Qt spezifischen glue-Code schreiben, dafür ist das resultat mMn eleganter und du musst dich weniger um locking kümmern.
 
Zurück
Oben