IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Multithreading Discussion :

comment lancer un programme dans un nouveau thread


Sujet :

Multithreading

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 18
    Points : 17
    Points
    17
    Par défaut comment lancer un programme dans un nouveau thread
    Bonjour à tous,

    J'ai créer un petit programme en C++ et je l'ai interfacé avec Qt.
    De manière synthétique, j'ai un bouton qui lance un algo. J'aimerais le lancer dans un thread différent de l'IHM pour éviter de "freezer" mon interface. J'ai fait une recherche sur Google et j'ai découvert QtConcurrent::run qui semble faire ce que je veux (voir ici). Cependant lorsque je lance ma fenêtre et que je clique sur mon bouton, j'obtiens un "RunTime Error".

    Voici un résumé de mon code :

    Voici mon header :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    #ifndef FENPRINCIPALE_H
    #define FENPRINCIPALE_H
     
    #include <QPushButton>
    #include <QApplication>
    #include <QtGui>
    #include <QLabel>
    #include <QThread>
    #include <QtConcurrentRun>
    #include <QFuture>
    #include <QFutureWatcher>
     
    class FenPrincipale : public QMainWindow
    {
         Q_OBJECT
     
         public:
            // Constructeur
            FenPrincipale();
     
            // Attributs
            QPushButton *bouton1;
     
            // Methodes
            void algo();
     
        // Slots
        public slots:
            void SlotAlgo();
    };
    #endif // FENPRINCIPALE_H
    Voici mon .cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    #include "FenPrincipale.h"
     
    FenPrincipale::FenPrincipale()
    {
    bouton1 = new QPushButton("Lancer algo");
    QObject::connect(bouton1, SIGNAL(clicked()),this, SLOT(SlotAlgo()));
    }
     
    void FenPrincipale::algo()
    {
       // time-consuming code
       double sum;
       for (int i=1; i<100000; i++)
       {
          for (int j=1; j<100000; j++)
          {
             sum = sum * i / j;
          }
       }
    }
     
    void FenPrincipale::SlotAlgo()
    {
        QFuture<void> future=QtConcurrent::run(this,&FenPrincipale::algo);
        future.waitForFinished();
    }

    Pouvez-vous me dire s'il y a une erreur que je ne vois pas, notamment dans FenPrincipale::SlotAlgo() ?
    Merci d'avance pour votre patience et votre aide .

  2. #2
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    http://qt.developpez.com/faq/?page=Thread devrait t'être d'une grande aide

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 18
    Points : 17
    Points
    17
    Par défaut
    Merci mais ce que je cherche, c'est une explication simple de la manière dont fonctionne QtConcurrent (et surtout la méthode run) pour ensuite pouvoir comprendre et débugger ce que j'ai écrit. J'ai déjà lu et essayé d'appliquer ce qui est indiqué dans la doc de Qt mais je n'y parviens pas.

  4. #4
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Pourquoi ne pas hériter de QThread et implémenter run() pour qu'elle réalise ton algo ?

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Yihaa Voir le message
    Pouvez-vous me dire s'il y a une erreur que je ne vois pas, notamment dans FenPrincipale::SlotAlgo() ?
    Merci d'avance pour votre patience et votre aide .
    C'est ce code qui plante???
    Le seule problème que je vois c'est que tu utilise une fonction de ton QObject dans la thread. Car un QObject n'est pas prévue pour être utilisé par plusieurs thread en même temps. Mais comme tu n'utilise rien de la classe, y as pas de raison que cela plante.

    Et attention, future.waitForFinished() est bloquante. Pour ne pas freezer l'ihm, utilise un QFutureWatcher et s'il faut une eventloop locale.

    Citation Envoyé par Alp Voir le message
    Pourquoi ne pas hériter de QThread et implémenter run() pour qu'elle réalise ton algo ?
    Pourquoi s'embêter à faire une thread si on peut éviter
    Après faut voir ce qu'il veut vraiment faire bien sure.

  6. #6
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par yan Voir le message
    Pourquoi s'embêter à faire une thread si on peut éviter
    Après faut voir ce qu'il veut vraiment faire bien sure.
    Bah si l'algo calcule quelque chose, j'verrais bien un slot dans sa fenêtre principale qui serait appelé quand le calcul est fini, prenant en argument le résultat, et l'affichant dans sa fenêtre principale (je suppose).

  7. #7
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Alp Voir le message
    Bah si l'algo calcule quelque chose, j'verrais bien un slot dans sa fenêtre principale qui serait appelé quand le calcul est fini, prenant en argument le résultat, et l'affichant dans sa fenêtre principale (je suppose).
    Tu peut aussi faire cela avec les concurrents et QFutureWatcher
    L'avantage c'est que concurrent permet d'utiliser un nombre de thread le mieux adapté à l'environnement.

    Le run est très pratique pour faire un traitement long dans un thread sans écrire de thread. Bien sure c'est pas magique. Si run exécute la méthode d'une classe, la fonction dot être reentrant et la classe ne doit pas être utilisé avant la fin du run. Si run exécute une méthode, il faut mieux quelle soit thread safe.

    Le seule avantage que je voie ici du thread, c'est de pouvoir envoyer un signal n'importe quand perdant l'éxécution du thread. Et la possibilité de stopper le calcul à n'importe quel endroit.

    Bien sure, il faudrait connaitre le vrai algo pour répondre plus précisément.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 18
    Points : 17
    Points
    17
    Par défaut
    Vous avez raison, j'ai trop simplifié mon code pour que vous soyez en mesure de m'aider.

    Ma classe FenPrincipale possède un attribut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QProgressBar *progression;
    que je mets à jour en fonction de la progression de l'algorithme.

    Plus précisément, la méthode algo contient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    for(int i=1;i<100;i++)
    {
                // Calcul
                //...
                //...
     
                emit monSignalProgression(i);
                progression->update();
    }
    et mon .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    #ifndef FENPRINCIPALE_H
    #define FENPRINCIPALE_H
     
    #include <QPushButton>
    #include <QApplication>
    #include <QtGui>
    #include <QLabel>
    #include <QThread>
    #include <QtConcurrentRun>
    #include <QFuture>
    #include <QFutureWatcher>
     
    class FenPrincipale : public QMainWindow
    {
         Q_OBJECT
     
         public:
            // Constructeur
            FenPrincipale();
     
            // Attributs
            QPushButton *bouton1;
     
            // Methodes
            void algo();
     
        // Slots
        public slots:
            void SlotAlgo();
        signals
            void monSignalProgression(int);
    };
    #endif // FENPRINCIPALE_H
    Le seule problème que je vois c'est que tu utilise une fonction de ton QObject dans la thread. Car un QObject n'est pas prévue pour être utilisé par plusieurs thread en même temps. Mais comme tu n'utilise rien de la classe, y as pas de raison que cela plante.
    Je pense que Yan a mis le doigt sur mon problème. En effet, ma QProgressBar et ma méthode algo appartiennent au même QObject. C'est surement ça qui pose problème..

    J'essaie d'y réfléchir et je vous tiens au courant de mon avancée.

  9. #9
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Je débute avec les threads dans Qt alors je vais essayé de ne pas dire (trop ?) de bêtises.

    Puisque ta fonction n'as pas d'argument, tu peux lancer directement par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QFuture<void> future = QtConcurrent::run(FenPrincipale::algo);
    Personnellement, je préfère utiliser Qthread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    class MyThread
     : public QThread
    {
     Q_OBJECT
     
     public:
      void run()
      {
       for(int ii=0; ii<1000000; ++ii)
       {
        // long calcul ici...
        if( (ii%10000) == 0)
         emit(update(ii));
       }
      }
     
      signals:
       void thUpdate(int value);
    };
     
    class MyWin
     : public QMainWindow
    {
     Q_OBJECT
     
     public:
      MyWin() : QMainWindow()
      {
       QPushButton* btn = new QPushButton("Lancer");
       connect(btn, SIGNAL(clicked()), this, SLOT(btnClicked()));
     
       th_ = new MyThread();
       connect(th, SIGNAL(thUpdate(int)), this, SLOT(thUpdate(int)));
      }
     
     private:
       MyTherad* th_;
     
     public slots:
      void btnClicked()
      {
       if( !th_->isRunning() )
        th->start();
      }
     
      void thUpdate(int value)
      {
       // mettre à jour ta QProgressBar
      }
    };
    J'utilise ici un thread lancé lors de la création de la fenêtre et relancé à chaque clic.

    Remarques :
    - ne pas refresh ta QProgressBar à chaque itération de ta boucle de calcul
    - si tu veux lancer plusieurs fois le calcul en parallèle, tu peux utiliser QThreadPool

  10. #10
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Yihaa Voir le message
    En effet, ma QProgressBar et ma méthode algo appartiennent au même QObject. C'est surement ça qui pose problème.
    Donc oui c'est bien le problème. Surtout si tu appel la progressbar
    http://qt.developpez.com/faq/?page=Thread#ihm-thread

    Donc tu as le choix :
    1- ta boucle for est parraléllisable : QtConcurrent::map ou QtConcurrent:mappedReduced) et QFuturWatcher peut correspondre parfaitement
    http://qt.developpez.com/doc/4.5/qtc...rogressdialog/

    2- ta boucle for n'est pas parallélisable : tu va devoir faire un thread

  11. #11
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Puisque ta fonction n'as pas d'argument, tu peux lancer directement par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QFuture<void> future = QtConcurrent::run(FenPrincipale::algo);
    Non, parce qu'il faut le pointeur sur la classe. Si elle était static, oui ca marcherai.

    si tu veux lancer plusieurs fois le calcul en parallèle, tu peux utiliser QThreadPool
    Si tu créé un thread, comment fait tu pour utiliser le thread pool? et comment fait tu pour emettre un signal?

  12. #12
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    En effet pour QtConcurrent.

    Pour QRunnable, il n'est pas possible de s'en sortir quand même, soit en héritant de QRunnins et QObjet (pour pouvoir lancer des signals) en même temps, soit en gardant un pointeur vers la fenêtre principale ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MyThread
     : public QRunning, public QObject
    {
     ...
     signals:
      void thUpdate();
    };
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class MyThread
     : public QRunning
    {
     public:
      MyThread(MyWin* parent);
     
      void run()
      {
       // calculs ...
       parent_->updateProgressBar(value);
      }
    };
     
    class MyWin
     : public QMainWindow
    {
     ...
     signals:
      void update(int value);
     
     void updateProgressBar(int value)
     {
      connect(this, SIGNAL(update(int), progressBar_, SLOT(update(int)));
      emit( update(value) );
     }
    };
    PS: au fait, un lien intéressant : http://qt-quarterly.developpez.com/q...reactivite-ihm

  13. #13
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Pour QRunnable, il n'est pas possible de s'en sortir quand même, soit en héritant de QRunnins et QObjet (pour pouvoir lancer des signals) en même temps, soit en gardant un pointeur vers la fenêtre principale ?
    Et tu tombe dans le iège d'utilisation d'un QObject entre plusieur thread .
    1- il faut hérité de QObject en premier
    2- regarde par ici http://qt.developpez.com/faq/?page=Thread
    3- comme un signal est thread safe, ça devrais marcher. Mais vue tous les risque annexe, je conseil de créé un QThread.

    Citation Envoyé par gbdivers Voir le message
    PS: au fait, un lien intéressant : http://qt-quarterly.developpez.com/q...reactivite-ihm
    http://qt-quarterly.developpez.com/q...eactivite-ihm/

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 18
    Points : 17
    Points
    17
    Par défaut
    Merci à tous pour vos explications. Grâce à vous, j'ai pû trouver mon erreur : on ne peut pas utiliser 2 méthodes appartenant au même QObject dans 2 thread différents.

    Pour mon cas particulier, http://qt.developpez.com/doc/4.5/qtc...rogressdialog/ décrit la méthode à suivre.

    La page http://qt-quarterly.developpez.com/q...eactivite-ihm/ est également très intéressante.

    Encore merci !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Lancer un form dans un nouveau thread
    Par Colbix dans le forum Langage
    Réponses: 2
    Dernier message: 23/04/2010, 13h25
  2. Réponses: 2
    Dernier message: 27/12/2005, 11h47
  3. Comment lancer un programme au démarrage de Windows ?
    Par nesquik dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 29/07/2005, 17h48
  4. Comment lancer une erreur dans une procédure stockée
    Par borgfabr dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 17/05/2005, 17h06
  5. Réponses: 8
    Dernier message: 05/06/2002, 11h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo