Developpez.com - Qt
X

Choisissez d'abord la catégorieensuite la rubrique :

Viadeo Twitter Facebook Share on Google+   
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Ré-entrance et thread-safety

Dans la documentation, les termes ré-entrance et thread-safe sont employés pour évaluer de quelle manière les classes et les fonctions peuvent être utilisées dans les applications multi-thread.

Introduction

  • Une fonction thread-safe peut être appelée simultanément depuis de multiples threads, même si les invocations utilisent des données partagées, car la totalité des références sur les données partagées sont sérialisées.
  • Une fonction ré-entrante peut aussi être appelée simultanément depuis de multiples 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 de manière sûre depuis de multiples threads, tant que chaque thread utilise une instance différente de la classe. La classe est thread-safe si ses fonctions membres peuvent être appelées de manière sûre depuis plusieurs threads, même si la totalité des threads utilisent la même instance de la classe.

Les classes C++ sont souvent ré-entrantes, simplement parce qu'elles accèdent uniquement à leurs propres données membres. Tout thread peut appeler une fonction membre sur une instance d'une classe ré-entrante, tant qu'aucun autre thread n'appelle une fonction membre de la même instance de la classe en même temps. 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;
};

Cette classe n'est pas thread-safe : si plusieurs threads tentent de modifier la donnée membre n, le résultat sera indéfini. Ceci est dû aux opérateurs ++ et - - qui ne sont pas toujours atomiques. En effet, ceux-ci s'incrémentent selon trois instructions/code machine :

  1. Chargement de la valeur de la variable dans un registre.
  2. Incrémentation ou décrémentation de la variable du registre.
  3. Stockage de la valeur du registre dans la mémoire principale.

Si un thread A et un thread B chargent simultanément l'ancienne valeur de la variable, incrémentent leur registre, puis la stockent de nouveau, ils finissent par s'écraser les uns les autres. Au final, la variable n'est incrémentée qu'une seule fois !

Clairement, l'accès doit être sérialisé : le thread A doit exécuter les étapes 1, 2 et 3 sans interruption (atomiquement) avant que le thread B ne puisse exécuter les mêmes étapes ; ou vice versa. Une manière simple de créer une classe thread-safe est de protéger tous les accès aux données membres 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 appelé, à la fin de la fonction. Le verrouillage du mutex assure que l'accès depuis différents threads sera sérialisé. La donnée membre mutex est déclarée avec le qualificateur mutable car nous avons besoin de verrouiller et de déverrouiller le mutex dans value(), qui est une fonction constante (const).

Beaucoup de classes de Qt sont ré-entrantes, mais elles ne sont pas rendues thread-safe car car cette transformation conduirait à s'exposer à des répétitions de verrouillage et de déverrouillage supplémentaires d'un QMutex. Par exemple, QString est réentrant mais pas thread-safe. Simultanément depuis plusieurs threads, vous pouvez accéder de manière sûre à des instances différentes de QString, mais pas à une même instance (excepté si vous protégez l'accès vous-même avec un QMutex).

Quelques classes et fonctions de Qt sont thread-safe. Elles sont principalement des classes apparentées à des threads (par exemple, QMutex) et à des fonctions fondamentales (par exemple, QCoreApplication::postEvent()).

Note : Les classes de Qt ne sont documentées comme thread-safe seulement si elles sont destinées à être utilisées dans de multiples threads.

Note : La terminologie dans le domaine du multithreading n'est pas entièrement standardisée. POSIX utilise les définitions de ré-entrante et de thread-safety qui sont quelque peu différentes pour son API C. Lors de l'utilisation d'autres bibliothèques de classes C++ orientées objet avec Qt, assurez vous que les définitions soient comprises.

Remerciements

Merci à <!amnell!> pour la traduction et à Jonathan Courtois ainsi qu'à Philippe Beaucart pour leur relecture !

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7
Copyright © 2017 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur, une redirection cassée ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
Responsable bénévole de la rubrique Qt : Thibaut Cuvelier -