Réentrance et sécurité des threads
Tout au long de la documentation, les termes " réentrant " et " thread-safe" sont utilisés pour marquer les classes et les fonctions afin d'indiquer comment elles peuvent être utilisées dans des applications multithread :
- Une fonction thread-safe peut être appelée simultanément par plusieurs threads, même si les invocations utilisent des données partagées, car toutes les références aux données partagées sont sérialisées.
- Une fonction réentrante peut également être appelée simultanément par plusieurs threads, mais uniquement si chaque invocation utilise ses propres données.
Par conséquent, une fonction thread-safe est toujours réentrante, mais une fonction réentrante n'est pas toujours thread-safe.
Par extension, une classe est dite réentrante si ses fonctions membres peuvent être appelées en toute sécurité à partir de plusieurs threads, à condition que chaque thread utilise une instance différente de la classe. La classe est thread-safe si ses fonctions membres peuvent être appelées en toute sécurité à partir de plusieurs threads, même si tous les threads utilisent la même instance de la classe.
Remarque : les classes Qt ne sont documentées comme sûres pour les threads que si elles sont destinées à être utilisées par plusieurs threads. Si une fonction n'est pas marquée comme thread-safe ou réentrante, elle ne doit pas être utilisée par plusieurs threads. Si une classe n'est pas marquée comme thread-safe ou réentrante, une instance spécifique de cette classe ne doit pas être accessible à partir de différents threads.
Réentrance
Les classes C++ sont souvent réentrantes, simplement parce qu'elles n'accèdent qu'aux données de leurs propres membres. N'importe quel thread peut appeler une fonction membre sur une instance d'une classe réentrante, tant qu'aucun autre thread ne peut appeler une fonction membre sur la même instance de la classe au même moment. Par exemple, la classe Counter ci-dessous est réentrante :
class Counter { public: Counter() { n = 0; } void increment() { ++n; } void decrement() { --n; } int value() const { return n; } private: int n; };
La classe n'est pas thread-safe, car si plusieurs threads tentent de modifier le membre de données n, le résultat est indéfini. En effet, les opérateurs ++ et -- ne sont pas toujours atomiques. En effet, ils s'étendent généralement sur trois instructions machine :
- Charger la valeur de la variable dans un registre.
- Incrémenter ou décrémenter la valeur du registre.
- Stocker la valeur du registre dans la mémoire principale.
Si le thread A et le thread B chargent simultanément l'ancienne valeur de la variable, incrémentent leur registre et le stockent à nouveau, ils finissent par s'écraser l'un l'autre, alors que la variable n'est incrémentée qu'une seule fois !
Sécurité des threads
Il est clair que l'accès doit être sérialisé : Le thread A doit effectuer les étapes 1, 2, 3 sans interruption (atomiquement) avant que le thread B puisse effectuer les mêmes étapes ; ou vice versa. Une façon simple de rendre la classe thread-safe est de protéger tous les accès aux membres de données avec un QMutex:
class Counter { public: Counter() { n = 0; } void increment() { QMutexLocker locker(&mutex); ++n; } void decrement() { QMutexLocker locker(&mutex); --n; } int value() const { QMutexLocker locker(&mutex); return n; } private: mutable QMutex mutex; int n; };
La classe QMutexLocker verrouille automatiquement le mutex dans son constructeur et le déverrouille lorsque le destructeur est invoqué, à la fin de la fonction. Le verrouillage du mutex garantit que les accès provenant de différents threads seront sérialisés. Le membre de données mutex est déclaré avec le qualificatif mutable parce que nous devons verrouiller et déverrouiller le mutex dans value(), qui est une fonction const.
Notes sur les classes Qt
De nombreuses classes Qt sont réentrantes, mais elles ne sont pas rendues sûres pour les threads, parce que les rendre sûres pour les threads entraînerait le surcoût du verrouillage et du déverrouillage répétés d'un QMutex. Par exemple, QString est réentrant mais n'est pas sûr pour les threads. Vous pouvez accéder en toute sécurité à différentes instances de QString à partir de plusieurs threads simultanément, mais vous ne pouvez pas accéder en toute sécurité à la même instance de QString à partir de plusieurs threads simultanément (à moins que vous ne protégiez vous-même les accès à l'aide d'un QMutex).
Certaines classes et fonctions de Qt sont sûres pour les threads. Il s'agit principalement des classes liées aux threads (par exemple QMutex) et des fonctions fondamentales (par exemple QCoreApplication::postEvent()).
Remarque : la terminologie dans le domaine du multithreading n'est pas entièrement normalisée. POSIX utilise des définitions de réentrant et de thread-safe qui sont quelque peu différentes pour ses API C. Lorsque vous utilisez d'autres bibliothèques de classes C++ orientées objet avec Qt, assurez-vous que les définitions sont comprises.
© 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.