Technologies de multithreading dans Qt
Qt offre de nombreuses classes et fonctions pour travailler avec des threads. Vous trouverez ci-dessous quatre approches différentes que les programmeurs Qt peuvent utiliser pour mettre en œuvre des applications multithread.
QThread : API de bas niveau avec boucles d'événements optionnelles
QThread QThread est la base de tout le contrôle des threads dans Qt. Chaque instance de QThread représente et contrôle un thread.
QThread QThread peut être soit instancié directement, soit sous-classé. L'instanciation d'une instance QThread fournit une boucle d'événements parallèle, permettant aux slots QObject d'être invoqués dans un thread secondaire. La sous-classification d'un QThread permet à l'application d'initialiser le nouveau thread avant de démarrer sa boucle d'événements, ou d'exécuter un code parallèle sans boucle d'événements.
Voir les exemples QThread class reference et threading pour des démonstrations sur l'utilisation de QThread.
QThreadPool et QRunnable : Réutilisation des threads
La création et la destruction fréquentes de threads peuvent être coûteuses. Pour réduire ce coût, les threads existants peuvent être réutilisés pour de nouvelles tâches. QThreadPool est une collection de QThreads réutilisables.
Pour exécuter du code dans l'un des threads d'un QThreadPool, réimplémentez QRunnable::run() et instanciez le sous-classé QRunnable. Utilisez QThreadPool::start() pour placer QRunnable dans la file d'attente d'exécution de QThreadPool. Lorsqu'un thread devient disponible, le code contenu dans QRunnable::run() s'exécute dans ce thread.
Chaque application Qt dispose d'un pool de threads global, accessible via QThreadPool::globalInstance(). Ce pool de threads global maintient automatiquement un nombre optimal de threads en fonction du nombre de cœurs du processeur. Cependant, un QThreadPool séparé peut être créé et géré explicitement.
Qt Concurrent: Utilisation d'une API de haut niveau
Le module Qt Concurrent fournit des fonctions de haut niveau qui traitent certains modèles courants de calcul parallèle : map, filter et reduce. Contrairement à l'utilisation de QThread et QRunnable, ces fonctions ne nécessitent jamais l'utilisation de primitives de threading de bas niveau telles que les mutex ou les sémaphores. Au lieu de cela, elles renvoient un objet QFuture qui peut être utilisé pour récupérer les résultats des fonctions lorsqu'ils sont prêts. QFuture peut également être utilisé pour interroger l'état d'avancement du calcul et pour mettre en pause/reprendre/annuler le calcul. Pour plus de commodité, QFutureWatcher permet d'interagir avec QFuturepar le biais de signaux et de slots.
Qt ConcurrentLes algorithmes de mapping, de filtrage et de réduction du module distribuent automatiquement les calculs sur tous les cœurs de processeur disponibles, de sorte que les applications écrites aujourd'hui continueront à s'adapter lorsqu'elles seront déployées ultérieurement sur un système disposant de plus de cœurs.
Ce module fournit également la fonction QtConcurrent::run(), qui permet d'exécuter n'importe quelle fonction dans un autre thread. Cependant, QtConcurrent::run() ne prend en charge qu'un sous-ensemble de fonctions disponibles pour les fonctions map, filter et reduce. La fonction QFuture peut être utilisée pour récupérer la valeur de retour de la fonction et pour vérifier si le thread est en cours d'exécution. Cependant, un appel à QtConcurrent::run() n'utilise qu'un seul thread, ne peut pas être mis en pause/repris/annulé et ne peut pas être interrogé sur l'état d'avancement.
Voir la documentation du module Qt Concurrent pour plus de détails sur les différentes fonctions.
WorkerScript : Le threading en QML
Le type QML WorkerScript permet au code JavaScript de s'exécuter en parallèle avec le thread de l'interface graphique.
Chaque instance WorkerScript peut être associée à un script .js. Lorsque WorkerScript.sendMessage() est appelé, le script s'exécute dans un thread distinct (et un QML context distinct). Lorsque le script a fini de s'exécuter, il peut renvoyer une réponse au fil d'exécution de l'interface graphique, qui invoquera le gestionnaire de signal WorkerScript.onMessage().
L'utilisation de WorkerScript est similaire à l'utilisation d'un worker QObject qui a été déplacé dans un autre thread. Les données sont transférées entre les threads par le biais de signaux.
Voir la documentation WorkerScript pour plus de détails sur l'implémentation du script et pour une liste des types de données qui peuvent être transférées entre les threads.
Choisir une approche appropriée
Comme nous l'avons démontré ci-dessus, Qt propose différentes solutions pour développer des applications threadées. La bonne solution pour une application donnée dépend de l'objectif du nouveau thread et de la durée de vie du thread. Vous trouverez ci-dessous une comparaison des technologies de threading de Qt, suivie des solutions recommandées pour quelques exemples de cas d'utilisation.
Comparaison des solutions
| Fonctionnalité | QThread | QRunnable et QThreadPool | QtConcurrent::run() | Qt Concurrent (Carte, Filtre, Réduire) | WorkerScript |
|---|---|---|---|---|---|
| Langage | C++ | C++ | C++ | C++ | QML |
| La priorité des threads peut être spécifiée | Oui | Oui | |||
| Le thread peut exécuter une boucle d'événements | Oui | ||||
| Le fil d'exécution peut recevoir des mises à jour de données par le biais de signaux | Oui (reçues par un travailleur QObject) | Oui (reçu par WorkerScript) | |||
| Le fil d'exécution peut être contrôlé à l'aide de signaux | Oui (reçu par QThread) | Oui (reçu par QFutureWatcher) | |||
| Le fil d'exécution peut être contrôlé par l'intermédiaire d'un QFuture | Partiellement | Oui | |||
| Possibilité intégrée de mettre en pause/reprendre/annuler | Oui |
Exemples de cas d'utilisation
| Durée de vie d'un fil | Opération | Solution |
|---|---|---|
| Un appel | Exécuter une nouvelle fonction linéaire dans un autre thread, éventuellement avec des mises à jour de la progression pendant l'exécution. | Qt propose différentes solutions :
|
| Un appel | Exécuter une fonction existante dans un autre thread et obtenir sa valeur de retour. | Exécutez la fonction en utilisant QtConcurrent::run(). Demandez à QFutureWatcher d'émettre le signal finished() lorsque la fonction est revenue, et appelez QFutureWatcher::result() pour obtenir la valeur de retour de la fonction. |
| Un appel | Effectuer une opération sur tous les éléments d'un conteneur, en utilisant tous les cœurs disponibles. Par exemple, produire des vignettes à partir d'une liste d'images. | Utilisez la fonction QtConcurrent::filter() de Qt Concurrent pour sélectionner les éléments du conteneur et la fonction QtConcurrent::map() pour appliquer une opération à chaque élément. Pour plier la sortie en un seul résultat, utilisez plutôt les fonctions QtConcurrent::filteredReduced() et QtConcurrent::mappedReduced(). |
| Un appel/permanent | Effectuer un long calcul dans une application QML pure et mettre à jour l'interface graphique lorsque les résultats sont prêts. | Placez le code de calcul dans un script .js et attachez-le à une instance WorkerScript. Appelez WorkerScript.sendMessage() pour lancer le calcul dans un nouveau thread. Laissez le script appeler sendMessage() également, pour transmettre le résultat au thread de l'interface graphique. Traitez le résultat dans onMessage et mettez à jour l'interface graphique. |
| Permanent | Disposer d'un objet vivant dans un autre thread qui peut effectuer différentes tâches à la demande et/ou recevoir de nouvelles données à utiliser. | Sous-classez QObject pour créer un travailleur. Instanciez cet objet travailleur et un QThread. Déplacez le travailleur dans le nouveau thread. Envoyez des commandes ou des données à l'objet travailleur via des connexions de fente de signal en file d'attente. |
| Permanent | Exécuter de manière répétée une opération coûteuse dans un autre thread, où le thread n'a pas besoin de recevoir de signaux ou d'événements. | Écrire la boucle infinie directement dans une réimplémentation de QThread::run(). Démarrer le thread sans boucle d'événements. Laisser le thread émettre des signaux pour renvoyer des données au thread de l'interface graphique. |
© 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.