Retour sur une nouveauté de Qt 5.10 pour la programmation concurrente :
QThread::create() pour créer un fil d'exécution depuis une fonction anonyme

Le , par dourouc05, Responsable Qt & Livres
QThread est une ancienne classe de Qt : elle date de la version 2.2, sortie en septembre 2000. Elle sert à lancer du code dans un fil d’exécution séparé, par exemple pour éviter de geler l’interface graphique quand un code plus lourd est lancé. Depuis un certain temps, on dispose de deux manières d’utiliser QThread : soit créer une classe dérivée dans le seul objectif de surcharger la méthode run(), soit créer une classe ouvrière connectée aux signaux de QThread.

Cependant, Qt 5.10 apporte une nouvelle manière de créer un fil d’exécution avec QThread, en profitant des derniers ajouts de C++11 : QThread::create() prend en argument une fonction anonyme qui sera lancée dans le fil d’exécution. Cette API ressemble très fortement à la bibliothèque standard, en particulier la classe bien nommée std::thread. L’un des avantages principaux de cette manière de procéder est qu’elle évite de générer une sous-classe de QThread uniquement pour en réimplémenter une méthode. Contrairement à std::thread (mais de manière similaire aux autres utilisations de QThread), il faudra lancer le fil d’exécution manuellement par la suite. Cela laisse la possibilité de définir une priorité, de connecter des signaux, etc., avant l’exécution.

Code : Sélectionner tout
1
2
3
4
5
6
QThread *thread = QThread::create(myFunction);
 
thread->setObjectName("WorkerThread"); // name to appear in ps, task manager, etc.
connect(thread, &QThread::started, gui, &Gui::threadHasStarted);
 
thread->start();
Avec un compilateur C++17, il est aussi possible de passer plus d’un argument à QThread::create() : ils seront automatiquement passés à la fonction dans le fil d’exécution, tout comme avec std::thread.

Si cette fonction n’est implémentée que depuis Qt 5.10, ce n’est pas parce qu’elle est particulièrement dure à implémenter, plutôt grâce à un changement de politique au niveau de Qt. En effet, avant Qt 5, le code de Qt ne pouvait pas obliger à disposer de la STL (pour des raisons historiques). Depuis Qt 5.0, ce choix a été revu : il existe bien plus d’implémentations raisonnables de la STL. Ainsi, elle peut être utilisée pour implémenter des fonctionnalités de Qt, mais sans être visible à l’utilisateur. L’objectif est d’obtenir des binaires indépendants de la bibliothèque standard utilisée par Qt, de telle sorte qu’aucune contrainte n’est imposée sur les applications Qt — avec l’inconvénient que Qt doit recoder une partie de la STL.

Après moult débats, la décision a été prise pour Qt 5.10 d’abandonner cette politique : Qt peut maintenant exposer des types de la STL. Cela devrait permettre d’en simplifier largement le code (dès que les changements d’API seront autorisés, c’est-à-dire pour Qt 6 au plus tôt). L’inconvénient est que les utilisateurs ne pourront plus mélanger les implémentations de la STL. Par contre, cela a permis d’implémenter la méthode QThread::create sans devoir proposer d’implémentation de std::future dans Qt.

Source : New in Qt 5.10: QThread::create.


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse Signaler un problème

Avatar de ymoreau ymoreau - Membre émérite https://www.developpez.com
le 20/04/2018 à 9:39
Citation Envoyé par dourouc05 Voir le message
Contrairement à std::thread (mais de manière similaire aux autres utilisations de QThread), il faudra lancer le fil d’exécution manuellement par la suite. Cela laisse la possibilité de définir une priorité, de connecter des signaux, etc., avant l’exécution.
C'est la seule différence avec QtConcurrent::run si je ne me trompe pas ?
Parce que j'allais dire que pour exécuter une lambda dans un thread il y avait déjà plus simple que ce nouveau QThread::create
Avatar de Matthieu76 Matthieu76 - Membre éclairé https://www.developpez.com
le 20/04/2018 à 10:51
Mais ... ? Euh ... Je comprends pas trop l’intérêt du truc.
C'est pas déjà ce que fait un singleShot ?

Moi je fais un truc du genre pour faire de l'Asynchone :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
int resultOfSum;

void MySumAsync(int x, int y)
{
    QTimer::singleShot(0, this, SLOT( [] (int x, int y) {MySum(x, y);}));
}

void MySum(int x, int y)
{
    resultOfSum = x + y;
}
En gros dans mon code j'ai une classe Controller et à chaque appuie de bouton je démarre un singleShot et dedans j'appelle la fonction de mon controller associé. Es-ce une bonne méthode de faire cela ? Et vous, comment faîtes-vous ?

PS : Dans l'exemple je ne comprends pas cette variable &Gui::threadHasStarted
Avatar de mattf06 mattf06 - Candidat au Club https://www.developpez.com
le 21/04/2018 à 1:20
Citation Envoyé par Matthieu76 Voir le message
Mais ... ? Euh ... Je comprends pas trop l’intérêt du truc.
C'est pas déjà ce que fait un singleShot ?
L'utilisation de QTimer::singleShot te permet juste de retarder l'exécution de ta méthode. Si cela est en réponse à une action UI, donc dans le thread UI, ta méthode sera mise dans la queue d'événement UI et traitée ultérieurement. Si ta méthode fait un traitement long (plusieurs secondes par exemple) cela bloquera ta UI, d'où l'utilité des thread.
Avatar de Matthieu76 Matthieu76 - Membre éclairé https://www.developpez.com
le 23/04/2018 à 12:01
Un singleShot ne place pas la méthode à exécuter dans un thread ?
Avatar de ymoreau ymoreau - Membre émérite https://www.developpez.com
le 23/04/2018 à 15:03
Non. Sauf si l'objet récepteur est appartient à un autre thread, la règle classique signal/slot s'applique de la même façon avec le singleShot qu'avec n'importe quelle autre connexion.
Avatar de Matthieu76 Matthieu76 - Membre éclairé https://www.developpez.com
le 23/04/2018 à 18:51
Du coup, faut que j'utilise QtConcurrent::run pour run mes méthodes lors de l'appuis d'un bouton ? Es-ce le même fonctionnement qu'une Task en C# ? Merci d'avance pour votre aide
Responsable bénévole de la rubrique Qt : Thibaut Cuvelier -