Threads und QObjects
QThread erbt von ` QObject`. Es sendet Signale aus, um anzuzeigen, dass der Thread die Ausführung gestartet oder beendet hat, und stellt zudem einige Slots bereit.
Noch interessanter ist, dass ` QObject`s in mehreren Threads verwendet werden können, Signale aussenden, die Slots in anderen Threads aufrufen, und Ereignisse an Objekte senden können, die in anderen Threads „leben“. Dies ist möglich, weil jeder Thread über eine eigene Ereignisschleife verfügen darf.
Reentranz von QObject
QObject ist reentrant. Die meisten seiner Nicht-GUI-Unterklassen, wie beispielsweise „ QTimer “, „ QTcpSocket “, „ QUdpSocket “ und „ QProcess “, sind ebenfalls reentrant, wodurch es möglich ist, diese Klassen gleichzeitig aus mehreren Threads heraus zu verwenden. Beachten Sie, dass diese Klassen dafür ausgelegt sind, innerhalb eines einzigen Threads erstellt und verwendet zu werden; es ist nicht garantiert, dass das Erstellen eines Objekts in einem Thread und das Aufrufen seiner Funktionen aus einem anderen Thread funktioniert. Dabei sind drei Einschränkungen zu beachten:
- Das Kind eines „ QObject “ muss immer in dem Thread erstellt werden, in dem das Elternobjekt erstellt wurde. Dies bedeutet unter anderem, dass Sie das „ QThread “-Objekt (
this) niemals als Elternobjekt eines in diesem Thread erstellten Objekts übergeben sollten (da das „ QThread “-Objekt selbst in einem anderen Thread erstellt wurde). - Ereignisgesteuerte Objekte dürfen nur in einem einzigen Thread verwendet werden. Dies gilt insbesondere für den Timer-Mechanismus und den „ network module “. So können Sie beispielsweise keinen Timer starten oder eine Socket-Verbindung herstellen in einem Thread, der nicht der „ object's thread “ ist.
- Sie müssen sicherstellen, dass alle in einem Thread erstellten Objekte gelöscht werden, bevor Sie den „ QThread “ löschen. Dies lässt sich leicht bewerkstelligen, indem Sie die Objekte in Ihrer Implementierung von „ run()“ auf dem Stack anlegen.
Obwohl „ QObject “ reentrant ist, sind die GUI-Klassen, insbesondere „ QWidget “ und alle ihre Unterklassen, nicht reentrant. Sie dürfen nur vom Hauptthread aus verwendet werden. Wie bereits erwähnt, muss „ QCoreApplication::exec()“ ebenfalls von diesem Thread aus aufgerufen werden.
In der Praxis lässt sich die Unmöglichkeit, GUI-Klassen in anderen Threads als dem Hauptthread zu verwenden, leicht umgehen, indem zeitaufwändige Operationen in einen separaten Worker-Thread ausgelagert und die Ergebnisse im Hauptthread auf dem Bildschirm angezeigt werden, sobald der Worker-Thread fertig ist. Dieser Ansatz wurde bei der Implementierung des Mandelbrot-Beispiels und des „Blocking Fortune Client“-Beispiels verwendet.
Im Allgemeinen wird das Erstellen von QObjects vor dem „ QApplication “ nicht unterstützt und kann je nach Plattform zu seltsamen Abstürzen beim Beenden führen. Das bedeutet, dass auch statische Instanzen von „ QObject “ nicht unterstützt werden. Bei einer ordnungsgemäß strukturierten ein- oder mehrthreadigen Anwendung sollte der „ QApplication “ als Erstes erstellt und als Letztes zerstört werden QObject.
Thread-spezifische Ereignisschleife
Jeder Thread kann über eine eigene Ereignisschleife verfügen. Der Start-Thread startet seine Ereignisschleife mit ` QCoreApplication::exec()` oder – bei GUI-Anwendungen mit einem einzigen Dialog – manchmal mit ` QDialog::exec()`. Andere Threads können eine Ereignisschleife mit ` QThread::exec()` starten. Wie bei ` QCoreApplication` bietet auch ` QThread ` eine Funktion ` exit(int)` sowie einen Slot ` quit()`.
Eine Ereignisschleife in einem Thread ermöglicht es dem Thread, bestimmte Nicht-GUI-Qt-Klassen zu verwenden, die das Vorhandensein einer Ereignisschleife erfordern (wie z. B. QTimer, QTcpSocket und QProcess). Außerdem ermöglicht sie es, Signale aus beliebigen Threads mit Slots eines bestimmten Threads zu verbinden. Dies wird im folgenden Abschnitt „Signale und Slots über Threads hinweg “ näher erläutert.

Eine Instanz von ` QObject ` gilt als in dem Thread verortet, in dem sie erstellt wurde. Ereignisse an dieses Objekt werden von der Ereignisschleife dieses Threads verteilt. Der Thread, in dem eine Instanz von ` QObject ` verortet ist, kann über ` QObject::thread()` ermittelt werden.
Die Funktion ` QObject::moveToThread()` ändert die Thread-Affinität für ein Objekt und dessen untergeordnete Objekte (das Objekt kann nicht verschoben werden, wenn es ein übergeordnetes Objekt hat).
Der Aufruf von ` delete ` für ein ` QObject ` aus einem anderen Thread als demjenigen, dem das Objekt gehört (oder der Zugriff auf das Objekt auf andere Weise), ist unsicher, es sei denn, Sie stellen sicher, dass das Objekt zu diesem Zeitpunkt keine Ereignisse verarbeitet. Verwenden Sie stattdessen ` QObject::deleteLater()`, woraufhin ein ` DeferredDelete `-Ereignis gesendet wird, das die Ereignisschleife des Threads, dem das Objekt gehört, schließlich abfängt. Standardmäßig ist der Thread, dem ein ` QObject ` gehört, der Thread, der das ` QObject` erstellt hat – jedoch nicht mehr, nachdem ` QObject::moveToThread()` aufgerufen wurde.
Wenn keine Ereignisschleife läuft, werden keine Ereignisse an das Objekt übermittelt. Wenn Sie beispielsweise ein ` QTimer `-Objekt in einem Thread erstellen, aber niemals ` exec()` aufrufen, wird das ` QTimer ` niemals sein ` timeout()`-Signal auslösen. Auch der Aufruf von ` deleteLater()` funktioniert nicht. (Diese Einschränkungen gelten auch für den Hauptthread.)
Sie können jederzeit manuell Ereignisse an jedes beliebige Objekt in jedem beliebigen Thread senden, indem Sie die threadsichere Funktion ` QCoreApplication::postEvent()` verwenden. Die Ereignisse werden automatisch von der Ereignisschleife des Threads verteilt, in dem das Objekt erstellt wurde.
Ereignisfilter werden in allen Threads unterstützt, mit der Einschränkung, dass sich das überwachende Objekt im selben Thread befinden muss wie das überwachte Objekt. Ebenso kann ` QCoreApplication::sendEvent()` (im Gegensatz zu ` postEvent()`) nur dazu verwendet werden, Ereignisse an Objekte zu senden, die sich in dem Thread befinden, von dem aus die Funktion aufgerufen wird.
Zugriff auf QObject-Unterklassen aus anderen Threads
QObject und alle seine Unterklassen sind nicht threadsicher. Dies schließt das gesamte Ereignisübermittlungssystem ein. Es ist wichtig zu beachten, dass die Ereignisschleife möglicherweise Ereignisse an Ihre QObject -Unterklasse übermittelt, während Sie von einem anderen Thread aus auf das Objekt zugreifen.
Wenn Sie eine Funktion einer „ QObject “-Unterklasse aufrufen, die sich nicht im aktuellen Thread befindet, und das Objekt möglicherweise Ereignisse empfängt, müssen Sie jeden Zugriff auf die internen Daten Ihrer „ QObject “-Unterklasse mit einem Mutex absichern; andernfalls kann es zu Abstürzen oder anderem unerwünschten Verhalten kommen.
Wie andere Objekte befinden sich auch „ QThread “-Objekte in dem Thread, in dem das Objekt erstellt wurde –nicht in dem Thread, der beim Aufruf von ` QThread::run()` erstellt wird. Es ist im Allgemeinen unsicher, Slots in Ihrer „ QThread “-Unterklasse bereitzustellen, es sei denn, Sie schützen die Member-Variablen mit einem Mutex.
Andererseits können Sie Signale sicher aus Ihrer ` QThread::run()`-Implementierung aussenden, da die Signalausgabe threadsicher ist.
Signale und Slots über Threads hinweg
Qt unterstützt folgende Arten von Signal-Slot-Verbindungen:
- Auto Connection (Standard) Wenn das Signal in dem Thread ausgesendet wird, zu dem das empfangende Objekt eine Affinität hat, entspricht das Verhalten dem der direkten Verbindung. Andernfalls entspricht das Verhalten dem der Warteschlangenverbindung.“
- Direct Connection Der Slot wird sofort aufgerufen, sobald das Signal ausgesendet wird. Der Slot wird im Thread des Emitters ausgeführt, der nicht unbedingt der Thread des Empfängers sein muss.
- Queued Connection Der Slot wird aufgerufen, sobald die Kontrolle an die Ereignisschleife des Empfänger-Threads zurückkehrt. Der Slot wird im Empfänger-Thread ausgeführt.
- Blocking Queued Connection Der Slot wird wie bei der „Queued Connection“ aufgerufen, mit dem Unterschied, dass der aktuelle Thread blockiert, bis der Slot zurückkehrt.
Hinweis: Die Verwendung dieses Typs zum Verbinden von Objekten im selben Thread führt zu einem Deadlock.
- Unique Connection Das Verhalten entspricht dem der „Auto Connection“, jedoch wird die Verbindung nur hergestellt, wenn sie keine bereits bestehende Verbindung dupliziert. Das heißt, wenn dasselbe Signal bereits mit demselben Slot für dasselbe Objektpaar verbunden ist, wird die Verbindung nicht hergestellt und `connect()` gibt `
false` zurück.
Der Verbindungstyp kann durch Übergabe eines zusätzlichen Arguments an ` connect()` festgelegt werden. Beachten Sie, dass die Verwendung direkter Verbindungen, wenn Sender und Empfänger in unterschiedlichen Threads liegen, unsicher ist, wenn im Thread des Empfängers eine Ereignisschleife läuft – aus demselben Grund, aus dem der Aufruf einer beliebigen Funktion für ein Objekt, das in einem anderen Thread liegt, unsicher ist.
QObject::connect() selbst ist threadsicher.
Das Mandelbrot-Beispiel verwendet eine Queued-Verbindung für die Kommunikation zwischen einem Worker-Thread und dem Haupt-Thread. Um ein Einfrieren der Ereignisschleife des Haupt-Threads (und damit der Benutzeroberfläche der Anwendung) zu vermeiden, erfolgt die gesamte Berechnung des Mandelbrot-Fraktals in einem separaten Worker-Thread. Der Thread sendet ein Signal, sobald die Darstellung des Fraktals abgeschlossen ist.
In ähnlicher Weise verwendet das Beispiel „Blocking Fortune Client“ einen separaten Thread für die asynchrone Kommunikation mit einem TCP-Server.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.