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

Threads & Processus C++ Discussion :

wx thread : changer des champs de ma fenêtre depuis l'affichage


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 127
    Par défaut wx thread : changer des champs de ma fenêtre depuis l'affichage
    Bonjour à tous,

    Je précise que je n'ai pas une expérience très étoffée de l'usage des threads.

    Dans le cadre d'un projet, j'ai développé une application avec wx-widget faisant du calcul intensif et proposant une IHM de monitoring.

    Je dispose dans l'application de deux wxthreads:

    - Le thread principal dans lequel je crée la fenêtre de suivi du calcul.
    - Un thread de calcul.

    Ma fenetre de suivi, instance de la classe Monitoframe dérivée de wxFrame est référencée par un pointeur encaspulé dans un Singleton.

    Mon thread de calcul modifie les valeurs de certains champs des widgets de ma fenêtre (des wxStaticText et une wxGauge). Le problème est que mon thread de calcul appelle les fonctions de mon instance de monitoframe pour modifier l'affichage de l'avancement sans synchronisation.

    En fait mon code ressemble à ça:

    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
    // Initialisation de la fenêtre de monitoring
    bool application::OnInit()
    {
         wxInitAllImageHandlers();
         MonitoFrame* frame = new monitoFrame(0L); // On crée la fenêtre.
         ...
         SingletonParamsGlobals::getInstance()->lancerThreadCalcul(m, argc, argv); // On lance le thread de calcul, 
         ...
    }
     
     void SingletonParamsGlobals::lancerThreadCalcul(Commande* _m, int argc , char **argv)
    {
          t = new Tlaunch(_m, argc, argv);
          t->Create();
          t->Run();
    }
    Le code de lancement du thread de calcul ressemble à ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void* Entry(){
    if( TestDestroy() )
      return NULL;
           resultat = m->launch(_argc, _argv);
           exit(0);
     }
     int getResultat(){
      return resultat;
     }
    Dans le code de mon thread de calcul, je fais régulièrement appel à des méthodes de la classe MonitoFrame, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SingletonParamsGlobals::getInstance()->getFenetrePrincipale()->setAvancement(0);

    Lorsque je fais des appels "trop rapprochés" aux fonctions de Monitoframe, j'ai quelque fois un plantage violent. D'où mes questions:

    Pourquoi ai-je ce comportement ? un champ d'un wxStaticText est-il modifié par le thread de calcul alors que le thread principal gérant l'affichage essaie d'accéder à sa valeur pour l'afficher ?
    D'ailleurs, pourquoi le "repaint" de ma fenêtre est-il automatique lorsque par exemple, je modifie la valeur d'un wxStaticText ? Je pense que le problème vient de là, le thread principal demandant l'affichage d'un champ dont je modifie potentiellement la valeur de manière concurente au travers du thread principal.

    Avez-vous des liens vers des tutoriaux expliquant comme bien synchronizer la modification des valeurs d'une IHM depuis un thread de calcul ou simplement de petits conseils à me donner. Je suis un peu perdu.


    Cordialement,
    Benoît.

  2. #2
    Membre expérimenté Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Par défaut
    Hello,
    A ma connaissance, la plupart des Lib de GUI (voir toutes) ne sont pas thread-safe. Je me souviens avoir eu un paquet de soucis avec wxWidget à ce niveau et certaines libs (Qt pour ne pas la nommer) interdisent totalement la modification d'éléments d'interface dans un thread différent du principal. A mon avis, la solution la plus sûr est de modifier tes widgets dans le thread principal, notamment par l'intermédiaire du gestionnaire d'évènements. C'est très facile à mettre en place sous Qt, mais beaucoup moins drôle sous wxWidget. Regarde du coté de la fonction membre de wEvtHandler: AddPendingEvent qui permet de faire passer un évènement d'un thread quelconque au thread principal.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 127
    Par défaut
    Merci pour votre réponse,


    J'ai fait quelques recherches sur le web mais je n'ai pas trouvé d'exemple minimaliste illustrant ce que je désire faire. Beaucoup font comme moi, de manière non thread safe...

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 127
    Par défaut
    Voici les portions de code posant problème, simplifiées pour résumé le problème:

    header:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MonitoFrame: public wxFrame
    {
        MonitoFrame(wxWindow* parent,wxWindowID id=wxID_ANY);
        virtual ~monitoFrame();
        void setTextCalcul (std::string texteCalcul);
        void majGui();
        void OnTimer(wxTimerEvent& event);
    private:
        std::string _textCalcul;
        wxStaticText* StaticTextCalcul;
    };
    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
    28
    BEGIN_EVENT_TABLE(monitoFrame,wxFrame)
        EVT_TIMER(Id_Timer,   monitoFrame::OnTimer)
    END_EVENT_TABLE()
     
    monitoFrame::monitoFrame(wxWindow* parent,wxWindowID id) {
     
        Create(parent, wxID_ANY, _("spp.exe"), wxDefaultPosition, wxDefaultSize, wxSTAY_ON_TOP|wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, _T("wxID_ANY"));
        Panel1 = new wxPanel(this, ID_PANEL1, wxPoint(0,0), wxSize(360,272), wxTAB_TRAVERSAL, _T("ID_PANEL1"));
        StaticTextCalcul = new wxStaticText(Panel1, ID_STATICTEXT9, wxEmptyString, wxPoint(272,24), wxSize(8,13), 0, _T("ID_STATICTEXT9"));
        Center();
        MonTimer.SetOwner(this,Id_Timer);
        MonTimer.Start(50);
     
    }
     
    void monitoFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) {
        majAffichage();
    }
     
    // Fonction appelée dans le thread principal par le Timer toutes les 50 ms 
    void monitoFrame::majGui(){
        StaticTextCalcul->SetLabel(_textCalcul); // Conflit si le thread de calcul écrit _textCalcul pendant que le thread principal le lit ici.
    }
     
    // Fonction appelée par le Thread de calcul, actuellement potentiellement en même temps que majGui soit appelée par le thread principal
    void monitoFrame::setTextCalcul(std::string textCalcul){
        _textCalcul = textCalcul;
    }
    Le problème vient du fait que le thread de calcul modifie la valeur de _textCalcul au travers de l'appel de setTextCalcul pendant que le thread principal lit la valeur pour l'afficher dans la méthode majGui.

    Comment éviter ce problème facilement, avec un mutex, si oui, je n'en ai pas bien compris l'utilisation, quelqu'un pour m'expliquer?

  5. #5
    Membre expérimenté Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Par défaut
    Hello, désolé pour la réponse tardive, problème de connexion chez moi^^

    Donc oui, cela devrait marcher avec des mutex. Grossièrement, un mutex sert à "locker" une variable entre plusieurs thread, typiquement lorsque ces thread cherchent à accéder simultanément (au moins un accès en écriture) à celle-ci (il y a plusieurs post sur le sujet, faut juste les retrouver). Dans ton cas, cela va donner:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    // Fonction appelée dans le thread principal par le Timer toutes les 50 ms 
    void monitoFrame::majGui(){
        wxMutexLocker lock(m_mutex);
        StaticTextCalcul->SetLabel(_textCalcul); // Conflit si le thread de calcul écrit _textCalcul pendant que le thread principal le lit ici.
    }
     
    // Fonction appelée par le Thread de calcul, actuellement potentiellement en même temps que majGui soit appelée par le thread principal
    void monitoFrame::setTextCalcul(std::string textCalcul){
         wxMutexLocker lock(m_mutex);
        _textCalcul = textCalcul;
    }
    Avec m_mutex un wxMutex déclaré dans ta classe monitoFrame.

Discussions similaires

  1. [Toutes versions] programme pour changer des champs cellules
    Par varik dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 25/01/2012, 21h02
  2. commander l'affichage des champs d'une requête depuis un formulaire
    Par nicoosito dans le forum Requêtes et SQL.
    Réponses: 8
    Dernier message: 31/07/2010, 13h53
  3. [WD11] Énumération des champs d'une fenêtre
    Par dj_techno dans le forum WinDev
    Réponses: 4
    Dernier message: 11/03/2009, 15h05
  4. Réponses: 2
    Dernier message: 19/12/2006, 22h55
  5. [JAVASCRIPT] Renseigner un champ d'une fenêtre depuis une autre fenetre
    Par cobol60 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 21/07/2006, 13h05

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