Threads et QObjects
QThread hérite de QObject. Il émet des signaux pour indiquer que le thread a commencé ou terminé son exécution, et fournit également quelques slots.
Plus intéressant encore, QObjects peut être utilisé dans plusieurs threads, émettre des signaux qui invoquent des slots dans d'autres threads et envoyer des événements à des objets qui "vivent" dans d'autres threads. Cela est possible parce que chaque thread est autorisé à avoir sa propre boucle d'événements.
Réentrance de QObject
QObject QObject est réentrant. La plupart de ses sous-classes non-GUI, telles que QTimer, QTcpSocket, QUdpSocket et QProcess, sont également réentrantes, ce qui permet d'utiliser ces classes à partir de plusieurs threads simultanément. Notez que ces classes sont conçues pour être créées et utilisées à partir d'un seul thread ; la création d'un objet dans un thread et l'appel de ses fonctions à partir d'un autre thread ne sont pas garantis. Il y a trois contraintes à respecter :
- L'enfant d'une classe QObject doit toujours être créé dans le thread où le parent a été créé. Cela implique, entre autres, que vous ne devez jamais passer l'objet QThread (
this) comme parent d'un objet créé dans le thread (puisque l'objet QThread lui-même a été créé dans un autre thread). - Les objets événementiels ne peuvent être utilisés que dans un seul thread. Cela s'applique en particulier au mécanisme de minuterie et à network module. Par exemple, vous ne pouvez pas démarrer une minuterie ou connecter un socket dans un thread qui n'est pas object's thread.
- Vous devez vous assurer que tous les objets créés dans un thread sont supprimés avant de supprimer le QThread. Cela peut se faire facilement en créant les objets sur la pile dans votre implémentation run().
Bien que QObject soit réentrant, les classes GUI, notamment QWidget et toutes ses sous-classes, ne le sont pas. Elles ne peuvent être utilisées qu'à partir du thread principal. Comme indiqué précédemment, QCoreApplication::exec() doit également être appelé à partir de ce thread.
Dans la pratique, l'impossibilité d'utiliser les classes d'interface graphique dans d'autres threads que le thread principal peut facilement être contournée en plaçant les opérations qui prennent du temps dans un thread de travail séparé et en affichant les résultats à l'écran dans le thread principal lorsque le thread de travail est terminé. C'est l'approche utilisée pour mettre en œuvre l'exemple de Mandelbrot et l'exemple de Blocking Fortune Client.
En général, la création de QObjects avant QApplication n'est pas prise en charge et peut entraîner des plantages bizarres à la sortie, selon la plate-forme. Cela signifie que les instances statiques de QObject ne sont pas non plus prises en charge. Une application mono ou multithread correctement structurée devrait faire en sorte que QApplication soit le premier créé et le dernier détruit QObject.
Boucle d'événements par thread
Chaque thread peut avoir sa propre boucle d'événements. Le thread initial démarre sa boucle d'événements à l'aide de QCoreApplication::exec(), ou pour les applications GUI à dialogue unique, parfois QDialog::exec(). D'autres threads peuvent démarrer une boucle d'événements à l'aide de QThread::exec(). Comme QCoreApplication, QThread fournit une fonction exit(int) et un slot quit().
Une boucle d'événements dans un thread permet à ce dernier d'utiliser certaines classes Qt GUI non graphiques qui nécessitent la présence d'une boucle d'événements (telles que QTimer, QTcpSocket, et QProcess). Elle permet également de connecter des signaux provenant de n'importe quel thread à des slots d'un thread spécifique. Ceci est expliqué plus en détail dans la section Signaux et slots entre threads ci-dessous.

On dit d'une instance de QObject qu'elle vit dans le thread dans lequel elle a été créée. Les événements relatifs à cet objet sont distribués par la boucle d'événements de ce thread. Le thread dans lequel vit une instance QObject est disponible à l'aide de la fonction QObject::thread().
La fonction QObject::moveToThread() modifie l'affinité de thread pour un objet et ses enfants (l'objet ne peut pas être déplacé s'il a un parent).
Appeler delete sur un QObject à partir d'un thread autre que celui qui possède l' objet (ou accéder à l'objet d'une autre manière) n'est pas sûr, à moins que vous ne garantissiez que l'objet ne traite pas d'événements à ce moment-là. Utilisez QObject::deleteLater() à la place, et un événement DeferredDelete sera posté, que la boucle d'événements du fil d'exécution de l'objet reprendra éventuellement. Par défaut, le thread qui possède un QObject est celui qui crée le QObject, mais pas après que QObject::moveToThread() a été appelé.
Si aucune boucle d'événements n'est en cours d'exécution, les événements ne seront pas transmis à l'objet. Par exemple, si vous créez un objet QTimer dans un thread mais que vous n'appelez jamais exec(), le QTimer n'émettra jamais son signal timeout(). L'appel à deleteLater() ne fonctionnera pas non plus. (Ces restrictions s'appliquent également au fil d'exécution principal).
Vous pouvez manuellement envoyer des événements à n'importe quel objet dans n'importe quel thread et à n'importe quel moment en utilisant la fonction thread-safe QCoreApplication::postEvent(). Les événements seront automatiquement distribués par la boucle d'événements du thread dans lequel l'objet a été créé.
Les filtres d'événements sont pris en charge dans tous les threads, avec la restriction que l'objet de surveillance doit vivre dans le même thread que l'objet surveillé. De même, QCoreApplication::sendEvent() (contrairement à postEvent()) ne peut être utilisé que pour envoyer des événements à des objets vivant dans le thread à partir duquel la fonction est appelée.
Accès aux sous-classes de QObject depuis d'autres threads
QObject QObject et toutes ses sous-classes ne sont pas sûres pour les threads. Cela inclut l'ensemble du système d'envoi d'événements. Il est important de garder à l'esprit que la boucle d'événements peut fournir des événements à votre sous-classe QObject pendant que vous accédez à l'objet à partir d'un autre thread.
Si vous appelez une fonction sur une sous-classe QObject qui ne vit pas dans le thread courant et que l'objet peut recevoir des événements, vous devez protéger tous les accès aux données internes de votre sous-classe QObject à l'aide d'un mutex ; sinon, vous risquez d'avoir des plantages ou d'autres comportements indésirables.
Comme les autres objets, les objets QThread vivent dans le thread où l'objet a été créé - et non dans le thread qui est créé lorsque QThread::run() est appelé. Il n'est généralement pas sûr de fournir des slots dans votre sous-classe QThread, à moins que vous ne protégiez les variables membres avec un mutex.
D'un autre côté, vous pouvez émettre des signaux en toute sécurité à partir de votre implémentation de QThread::run(), car l'émission de signaux est sans danger pour les threads.
Signaux et slots entre threads
Qt prend en charge les types de connexion suivants entre les signaux et les slots :
- Auto Connection (par défaut) Si le signal est émis dans le thread avec lequel l'objet récepteur a une affinité, le comportement est le même que celui de la connexion directe. Sinon, le comportement est le même que celui de la connexion en file d'attente".
- Direct Connection Le slot est invoqué immédiatement, lorsque le signal est émis. Le slot est exécuté dans le thread de l'émetteur, qui n'est pas nécessairement le thread du récepteur.
- Queued Connection Le slot est invoqué lorsque le contrôle revient à la boucle d'événements du thread du récepteur. Le slot est exécuté dans le thread du récepteur.
- Blocking Queued Connection Le slot est invoqué comme pour la connexion en file d'attente, sauf que le thread en cours se bloque jusqu'à ce que le slot revienne.
Remarque : l'utilisation de ce type de connexion pour connecter des objets dans le même thread entraînera un blocage.
- Unique Connection Le comportement est le même que pour la connexion automatique, mais la connexion n'est établie que si elle ne duplique pas une connexion existante, c'est-à-dire que si le même signal est déjà connecté au même slot pour la même paire d'objets, la connexion n'est pas établie et connect() renvoie
false.
Le type de connexion peut être spécifié en passant un argument supplémentaire à connect(). Sachez que l'utilisation de connexions directes lorsque l'expéditeur et le destinataire vivent dans des threads différents n'est pas sûre si une boucle d'événements s'exécute dans le thread du destinataire, pour la même raison que l'appel de toute fonction sur un objet vivant dans un autre thread n'est pas sûr.
QObject::connect() lui-même est sûr pour les threads.
L'exemple de Mandelbrot utilise une connexion en file d'attente pour communiquer entre un thread de travail et le thread principal. Pour éviter de geler la boucle d'événements du thread principal (et, par conséquent, l'interface utilisateur de l'application), tous les calculs fractals de Mandelbrot sont effectués dans un thread de travail séparé. Le thread émet un signal lorsqu'il a terminé le rendu de la fractale.
De même, l'exemple du client Blocking Fortune utilise un thread séparé pour communiquer avec un serveur TCP de manière asynchrone.
© 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.