Réentrance et sécurité des threads
Dans l'ensemble de la documentation, les termes « réentrant » et « sans danger pour les threads » sont utilisés pour qualifier des classes et des fonctions afin d'indiquer comment elles peuvent être utilisées dans des applications multithread :
- Une fonction « thread-safe » peut être appelée simultanément depuis plusieurs threads, même lorsque les appels utilisent des données partagées, car toutes les références à ces données sont sérialisées.
- Une fonction réentrante peut également être appelée simultanément depuis plusieurs threads, mais uniquement si chaque appel 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é depuis 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é depuis plusieurs threads, même si tous les threads utilisent la même instance de la classe.
Remarque : les classesQt ne sont documentées comme « thread-safe » 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 depuis différents threads. Si une classe n’est pas signalée comme « thread-safe » ou « réentrante », il ne faut pas accéder à une instance spécifique de cette classe à partir de threads différents.
Réentrance
Les classes C++ sont souvent réentrantes, simplement parce qu’elles n’accèdent qu’à leurs propres données membres. N’importe quel thread peut appeler une fonction membre sur une instance d’une classe réentrante, à condition qu’aucun autre thread ne puisse 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 sûre pour les threads, car si plusieurs threads tentent de modifier le membre de données n, le résultat est indéfini. Cela s’explique par le fait que les opérateurs ++ et -- ne sont pas toujours atomiques. En effet, ils se décomposent généralement en trois instructions machine :
- Chargement de la valeur de la variable dans un registre.
- Incrémenter ou décrémenter la valeur du registre.
- Récupérer 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 la réécrivent, ils finissent par s'écraser mutuellement, et la variable n'est incrémentée qu'une seule fois !
Sécurité des threads
Il est évident que l’accès doit être sérialisé : le thread A doit effectuer les étapes 1, 2 et 3 sans interruption (de manière atomique) avant que le thread B ne puisse effectuer les mêmes étapes ; ou inversement. Un moyen simple de rendre la classe sûre pour les threads consiste à protéger tous les accès aux membres de données à l’aide d’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 appelé, à 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 `, car nous devons verrouiller et déverrouiller le mutex dans ` value()`, qui est une fonction `const`.
Remarques sur les classes Qt
De nombreuses classes Qt sont réentrantes, mais elles ne sont pas sécurisées pour les threads, car les rendre ainsi impliquerait une surcharge supplémentaire liée au verrouillage et au déverrouillage répétés d’un ` QMutex`. Par exemple, ` QString ` est réentrante mais n’est pas sécurisée 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 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 des termes « réentrant » et « thread-safe » qui diffèrent quelque peu pour ses API C. Lorsque vous utilisez d’autres bibliothèques de classes C++ orientées objet avec Qt, assurez-vous de bien comprendre ces définitions.
© 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.