Forum: PC-Programmierung QT: UIs durch Workerthreads steuern


von C++Lotte (Gast)


Lesenswert?

Hallo,

bei QT ist mir bekannt, dass nur der mainwindow Thread Änderungen 
GUI-Operationen zulässt. Soweit klar.

Frage: wenn ich mit QT neben dem mainwindow eine eigene 
QT-Designer-Formularklasse erstelle und die Zeile in der .cpp der neuen 
Formularklasse ist so:
Fenster::Fenster(QWidget *parent) : QWidget(parent, Qt::Window), ui(new 
Ui::Fenster)
und sorgt dafür, dass über das mainwindow über zb einen Button sich ein 
neues Fenster öffnet. In mainwindow.cpp steht dann beim Buttonclick:
fenster = new Fenster(this);
fenster->show();

Frage1:
gehört dieses zusätzliche QWidget Fenster dann auch zum mainwindow 
Thread?

Frage2:
Ist es möglich, dass Hintergrund-Worker-Threads je nach Bedarf im 
MainWindow sowie in weiteren solcher QWidget-Fenstern GUI Operationen 
ausführen können?
Beispiel ein Workerthread ändert ab und zu in MainWindow die Anzeige 
einer Zahl und andere Workerthreads ändern im QWidget-Fenster 
irgendwelche Werte in Zeilen in einer Tabelle.

Frage3:
Wenn Werte aus Workerthreads in jeweils einer eigenen Zeile einer 
Tabelle eines QWidget-Fensters angezeigt und regelmäßig aktualisiert 
werden sollen, gibt es irgendwelche Probleme mit gleichzeitigen 
GUI-Operationen der verschiedenen Threads? Muss das global dann per 
Mutex Synchronisiert werden oder kümmert sich QT darum wenn es mehrere 
GUI-Operationsanweisungen zugleich gibt?

Grüße

von Oliver S. (oliverso)


Lesenswert?

Alle GUI-Elemente, die du aus dem „Main“-Thread heraus anlegst, sind 
immer im richtigen Thread.

Kommunikation aus Worker-Threads mit dem GUI über direkte 
Funktionsaufrufe geht schief. Gemeinerweise funktioniert das manchmal 
doch, und Fehlermeldungen bekommst du auch nicht, so daß solche Fehler 
nicht immer offensichtlich sind.

Das geht sicher über den Signal/Slot-Mechanismus, der sorgt im 
Hintergrund für einen korrekte Zuordnung der Aufrufe zu den Threads.

Und natürlich sind alle nicht „thread-safen“ Methoden und Funktionen mit 
Mutexen zu synchronisieren.

Oliver

: Bearbeitet durch User
von C++Lotte (Gast)


Lesenswert?

> Alle GUI-Elemente, die du aus dem „Main“-Thread heraus anlegst, sind
> immer im richtigen Thread.
was heißt richtiger Thread, gibt es falsche Threads?
QWidget-Fenster haben dann einen eigenen GUI-Thread oder gehören zum 
GUI-MainThread?

> Kommunikation aus Worker-Threads mit dem GUI über direkte
> Funktionsaufrufe geht schief. Gemeinerweise funktioniert das manchmal
> doch, und Fehlermeldungen bekommst du auch nicht, so daß solche Fehler
> nicht immer offensichtlich sind.
>
> Das geht sicher über den Signal/Slot-Mechanismus, der sorgt im
> Hintergrund für einen korrekte Zuordnung der Aufrufe zu den Threads.

Ja der Signal/Slot-Mechanismus um im in der Main-GUI was zu ändern ist 
klar da hab ich auch schon ansätze gefunden:
zb: 
https://stackoverflow.com/questions/14545961/modify-qt-gui-from-background-worker-thread

Was ich noch nicht verstehe ist, wie das Ganze bei zusätzlichen 
QWidget-Fenstern, wie oben beschrieben, dann funktioniert.

von Rolf M. (rmagnus)


Lesenswert?

C++Lotte schrieb:
> Hallo,
>
> bei QT ist mir bekannt, dass nur der mainwindow Thread Änderungen
> GUI-Operationen zulässt. Soweit klar.

Das hat nicht speziell mit einem MainWindow zu tun. QMainWindow ist auch 
nur ein Widget wie jedes andere. In Qt sind die Instanzen der von 
QObject abgeleiteten Klassen immer an einen Thread gebunden. Alle 
GUI-Elememte müssen im Hauptthread "leben".

Die Qt-Doku sagt es so:
"As mentioned, each program has one thread when it is started. This 
thread is called the "main thread" (also known as the "GUI thread" in Qt 
applications). The Qt GUI must run in this thread. All widgets and 
several related classes, for example QPixmap, don't work in secondary 
threads. A secondary thread is commonly referred to as a "worker thread" 
because it is used to offload processing work from the main thread."

> Frage: wenn ich mit QT neben dem mainwindow eine eigene
> QT-Designer-Formularklasse erstelle und die Zeile in der .cpp der neuen
> Formularklasse ist so:
> Fenster::Fenster(QWidget *parent) : QWidget(parent, Qt::Window), ui(new
> Ui::Fenster)
> und sorgt dafür, dass über das mainwindow über zb einen Button sich ein
> neues Fenster öffnet. In mainwindow.cpp steht dann beim Buttonclick:
> fenster = new Fenster(this);
> fenster->show();
>
> Frage1:
> gehört dieses zusätzliche QWidget Fenster dann auch zum mainwindow
> Thread?

Zum "main thread", ja.

> Frage2:
> Ist es möglich, dass Hintergrund-Worker-Threads je nach Bedarf im
> MainWindow sowie in weiteren solcher QWidget-Fenstern GUI Operationen
> ausführen können?

Nein, die müssen immer von dem Thread aus ausgeführt werden, zu dem das 
entsprechende Objekt gehört - also für alle QWidgets vom main thread.

> Beispiel ein Workerthread ändert ab und zu in MainWindow die Anzeige
> einer Zahl und andere Workerthreads ändern im QWidget-Fenster
> irgendwelche Werte in Zeilen in einer Tabelle.

Nicht bei direktem Funktionsaufruf, aber bei Signal-Slot-Verbindungen 
geht das. Diese Verbindungen können nämlich auf mehrere Arten gemacht 
werden, und wenn Quell- und Zielobjekt in unterschiedlichen Threads 
leben, wird automatisch eine "queued connection" erzeugt. Das heißt, der 
Aufruf wird durch die Event-Loop geschleust.

> Frage3:
> Wenn Werte aus Workerthreads in jeweils einer eigenen Zeile einer
> Tabelle eines QWidget-Fensters angezeigt und regelmäßig aktualisiert
> werden sollen, gibt es irgendwelche Probleme mit gleichzeitigen
> GUI-Operationen der verschiedenen Threads?

Ja, gibt es.

C++Lotte schrieb:
>> Alle GUI-Elemente, die du aus dem „Main“-Thread heraus anlegst, sind
>> immer im richtigen Thread.
> was heißt richtiger Thread, gibt es falsche Threads?

Wie gesagt: Die Funktion eines QObjects dürfen nur aus dem Thread heraus 
aufgerufen werden, in dem es lebt, es sei denn, die Dokumentation sagt, 
dass die Funktion Thread Safe ist. Hier nochmal die Qt-Doku (von 
QObject) dazu:

"Thread Affinity

A QObject instance is said to have a thread affinity, or that it lives 
in a certain thread. When a QObject receives a queued signal or a posted 
event, the slot or event handler will run in the thread that the object 
lives in.

Note: If a QObject has no thread affinity (that is, if thread() returns 
zero), or if it lives in a thread that has no running event loop, then 
it cannot receive queued signals or posted events.

By default, a QObject lives in the thread in which it is created. An 
object's thread affinity can be queried using thread() and changed using 
moveToThread()."

> QWidget-Fenster haben dann einen eigenen GUI-Thread oder gehören zum
> GUI-MainThread?

Ausnahmslos alle Widgets und noch ein paar andere GUI-Objekte müssen in 
einem gemeinsamen GUI-Thread leben.

von BobbyX (Gast)


Lesenswert?

C++Lotte schrieb:

> Frage1:
> gehört dieses zusätzliche QWidget Fenster dann auch zum mainwindow
> Thread?

Leider hat Qt sehr viel Verwirrung mit den moveToThread Funktionen von 
QObjests geschaffen, wie man auch an dieser Fragestellung sieht.

Ein Objekt/Klasse "gehört" nicht zu einem Thread. Seine Funktionen 
werden in einem oder anderen Thread ausgeführt, falls die Applikation 
mehrere hat. Das ist alles.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.