Archives par mot-clé : Thread

Plus de folie avec les QThread

Publié dans C / C++ | Laisser un commentaire

La programmation avec des threads est complexe et ne doit jamais être prise à la légère. Tête froide, mutex et variables atomiques sont de rigueur si on veut s’éviter les affres de l’horreur.

Qt peut nous simplifier la vie. Il peut nous y aider en tout cas. Mais. Oui il y a un mais. En regardant la documentation disponible sur Internet, c’est le bazar car : il y a bien longtemps, entre Qt 4.4 et Qt 4.7, on utilisait les mêmes noms de méthodes (run) pour quelque chose de différent ! Du coup, même aujourd’hui on trouve de tout sur le Web.

Voici quelques conseils en vrac avant de pointer vers de la documentation intéressante.

Conseils en vrac

  • Si cela ne vous parle pas, allez regarder les définitions de thread-safe et re-entrant. En fait, renseignez-vous sur les threads avant d’utiliser les QThreads, vous gagnerez du temps.
  • Un QObject appartient au thread dans lequel il est créé, ou dans lequel il est déplacé (mais dans ce cas, il ne peut avoir de parents)
    • Corolaire : les enfants d’un QObject vivent dans le même thread que leur parent. Mais attention, les variables membres ne deviennent pas automatiquement enfant de leur QObject ! (bigre)
  • Si la notion de QEventLoop Qt ne vous parle pas, renseignez-vous !
  • De manière assez logique, on peut appeler tranquillement un QObject via plusieurs thread, donc la même fonction d’une même classe peut être appelée par différents threads. En général on évite. Pour faire de la communication inter-thread, le plus safe est d’utiliser les signaux / slots en mode QueueConnection (mode par défaut dans ce cas). Si le thread A émet un signal variableChanged(int), ce signal peut être catché par une classe dans le thread principal via un slot handleVariableChanged(int). Voir QueuedConnection
  • En fait, si on ne fait pas gaffe, notamment si on n’utilise pas les signaux / slots, ou si on utilise le mode DirectConnection, on peut sans se rendre compte avoir plusieurs threads qui modifient en même temps la même donnée. Le mécanisme de protection de base, c’est les mutex (QMutexLocker et QMutex sont vos amis). Mais on peut aussi jouer avec les variables atomiques. Plus difficile, pas toujours possible, mais indispensable si on veut éviter de manière fiable les interlocks.
  • Pour utiliser les signaux / slots entre thread, il faut au préalable s’assurer que les paramètres des signaux soient bien enregistrés avec Q_DECLARE_METATYPE(Type) et qRegisterMetaType<Type>(). Sans cela, en QueuedConnection le slot ne serait juste pas appelé (dommage, try again).
  • D’une manière générale, je préconise d’utiliser QConcurrent et QFutureWatcher qui encapsule le comportement des QThreads. C’est mieux, plus simple et presque toujours possible. Je ne suis pas le seul à le préconiser, c’est la doc Qt qui le dit.
  • Si on doit utiliser directement QThread, alors la lecture de la doc Qt et des articles de Maya et FabienPN est fortement encourager.

Continuer la lecture