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

C++/CLI Discussion :

Threads et TextBox


Sujet :

C++/CLI

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 3
    Par défaut Threads et TextBox
    Bonjour,

    Tout d'abord je voudrai remercier la communauté de developpez.net où j'ai pu trouver des solutions à la plupart de mes problèmes rien qu'en parcourant les forums, les FAQ et les tutoriaux depuis plus d'un an maintenant.

    Je réalise en ce moment un projet sous visual studio C++ 2008 basé sur une windows form sensée afficher des données reçues via un périphérique externe (type port série) dans une textBox. Il y a donc un thread (n°1) consacré aux contrôles de la windows Form et un autre thread (n°2) qui gère les communications avec le périphérique.

    Lorsqu'une trame est reçue par le thread n°2 je ne peux pas directement l'écrire dans la textBox de mon interface. J'ai donc mis en place un delegate pour pouvoir accéder aux routines de l'interface graphique. Il est déclaré dans un .h commun à tout le projet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    delegate void Ecrire(void);
    Le code à exécuter pour écrire dans la textbox est décrit dans la classe de la windows form(Projet::Form1). Pour l'instant je veux juste afficher OK à chaque réception d'une trame:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public: void EcrireTextBox(void)
    		{
    			textBox1->AppendText("OK");
    		}
    Enfin, dans le fichier .cpp contenant les fonctions bas de niveau de communication avec le port série je fais appel au délégué pour accéder à EcrireTextBox :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Projet::Form1 ^ pnt = gcnew Projet::Form1;
    Ecrire ^ delegue = gcnew Ecrire(pnt, &Projet::Form1::EcrireTextBox);
    delegue->Invoke();
    Quand je met tout ça en debug je vois que lorsqu'une trame est reçue je rentre bien dans la fonction "EcrireTextBox" et son code est exécuté. Par contre rien ne s'affiche dans la TextBox. En observant les outils de debug j'ai vu que le programme restait toujours dans le thread n°2 ce qui, pour moi, explique qu'il n'y a aucun effet sur la textBox (gérée par le thread n°1).

    Comment puis-je redonner la main à l'interface graphique (thread n°1) juste le temps de modifier la textbox?

    Merci d'avance

  2. #2
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Bonjour

    Ton problème est plus un problème .net qu'un problème C++.
    Il serait peut être préférable de l'exposer dans le forum .Net


    Sinon, et à vue de nez (bien que ayant perdu de vue le C++ depuis ... longtemps et surtout ne comprenant pas trop bien l'interêt de son usage en environnement managé) :

    - je ne comprends pas pourquoi tu instancies ta form avant d'écrire dans le TextBox.

    - si tu veux écrire depuis un thread secondaire, il faut que tu utilises le thread qui a instancié la forme pour accéder à un control quelconque.

    - pour cela, utiliser la méthode Invoke sur la Form et pas sur le delegate. (tester préalablement via la propriété InvokeRequired)

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 3
    Par défaut
    En effet je ne sais pas non plus pourquoi je créait une nouvelle instance avant l'appel de ma fonction. Ça m'apprendra à copier des exemples.
    J'ai donc créé une variable de type Projet::Form1 et pointant sur le thread principal contenant les contrôles.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static Projet::Form1 ^MainForm;
    et dans le code constructeur de la form :
    J'ai adapté l'appel de mon délégué comme tu me l'as indiqué :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Ecrire ^ pointeur = gcnew Ecrire(Projet::Form1::MainForm, &Projet::Form1::EcrireTextBox);
    if(Projet::Form1::MainForm->InvokeRequired) 
    {
    	Projet::Form1::MainForm->Invoke(pointeur);		 
     
    }
    Et ça marche ! merci beaucoup!

    J'ai utilisé le C++ car les fonctions bas-niveau pour la liaison série sont fournies par le constructeur du périphérique en C++. Si tu vois une autre solution beaucoup plus simple, ça m'intéresse. (Sachant que le fabricant propose aussi son code en C# mais je ne connais pas du tout ce langage).

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    STOP.
    Pas de variables globales déguisées.

    Si vous avez besoin d'accéder à un objet unique depuis n'importe quel endroit de votre programme, cela s'appel un singleton et cela s'implémente avec le Design Pattern Singleton, pas avec un membre static non thread-safe, non AppDomain-Aware etc. .

    Citation Envoyé par Bluedeep Voir le message
    - je ne comprends pas pourquoi tu instancies ta form avant d'écrire dans le TextBox.


    Vous devez avoir la form instancié pour avoir les contrôles qu'elle contient instanciés. Il faut que l'objet contrôle soit instancié pour pouvoir initialiser une de ses propriétés.

    Moi, je passerais tout simplement une référence de la form à la routine du thread (n°2) qu'elle utiliserait directement.



    Targus003, je pense que vous souffrez d'un syndrome extrêmement commun pour un programmeur C++ débutant dans les applications multi-threadés avec IHM, que j'appellerais le clivage Objet/Thread.

    La conception d'Objet en C++ n'est pas celle d'Objective-C ou de SmallTalk.
    Dans ces langages, chaque objet dispose de sa propre file de message et l'appel de méthode correspond à l'envoie synchrone d'un message et de la récupération de sa réponse. Un seul thread a le droit de lire la file de message d'un objet. Il y a donc cloisonnement strict entre les autres threads et l'objet. L'objet n'est associé qu'à un thread dans ces langages.
    (Je ne suis pas un spécialistes de ces langages, j'espère n'avoir pas dit trop de conneries )

    En C++, ce n'est pas du tout le cas. Un objet n'est pas "hébergé" dans un thread. Tous les threads peuvent appeler les méthodes de tous les objets. Le fait de déclarer une méthode dans la form ne garanti pas que celle-ci ne sera appelé que depuis le thread créateur de la form.

    Pour les coupeurs de cheveux en quatre, on peut avoir recoure au STA de COM ou à de multiples AppDomain en .NET pour simuler le comportement "à la smallTalk" de l'hébergement des objets dans des threads.
    C'est très complexe et ne correspondra pas aux habitudes de conception des programmeurs C++ expérimentés.

    Pour ma part, j'essaye de conserver ces problématiques loin de mon code par l'utilisation du principe d'encapsulation de la POO.
    En termes clairs, c'est d'encapsuler les méthodes qui sont "sensibles" au thread les appelants, dans une espèce de sas à thread.

    Le sas a, dans le cas d'une form, toujours la même tête:

    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
     
    public: void méthode_SAS(void)
    {
            if(InvokeRequired)
            {
                    Invoke(méthode_sensible);
            }
            else
            {
                    méthode_sensible();
            }
    }
     
    private: void méthode_sensible(void)
    {
            ...
    }
    Et ne jamais appeler méthode_sensible directement.

  5. #5
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    - je ne comprends pas pourquoi tu instancies ta form avant d'écrire dans le TextBox.


    Vous devez avoir la form instancié pour avoir les contrôles qu'elle contient instanciés. Il faut que l'objet contrôle soit instancié pour pouvoir initialiser une de ses propriétés.
    IL est évident qu'il faisait une instanciation de sa form à l'intérieur du code de celle-ci. Ce qui n'a aucun sens.

    Moi, je passerais tout simplement une référence de la form à la routine du thread (n°2) qu'elle utiliserait directement.
    Cela me semble évident. Mais on a pas le code global, donc inférer sur les détails d'implémentation est délicat.


    En C++, ce n'est pas du tout le cas. Un objet n'est pas "hébergé" dans un thread. Tous les threads peuvent appeler les méthodes de tous les objets. Le fait de déclarer une méthode dans la form ne garanti pas que celle-ci ne sera appelé que depuis le thread créateur de la form.
    Ici la problèmatique n'est pas du tout C++, mais .Net.

    C'est très complexe et ne correspondra pas aux habitudes de conception des programmeurs C++ expérimentés.
    Programmeurs qui founissent en général des codes déplorables dans les énvironnements managés ....

  6. #6
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Ici la problèmatique n'est pas du tout C++, mais .Net.


    Un objet est accessible par n'importe quel thread.
    Sur cet aspect, .NET, C++/CLI et C++ ont tous le même comportement.


    Exemple C++ non .NET, les MFC, où il n'y a pas un gramme de .NET, utilisent les des SendMessage et du hooking de fenêtre pour palier à ces "limitations".

    Où, dans la norme C++, est indiqué que les accès aux objets sont circonscrit à un thread "créateur"?

Discussions similaires

  1. Thread et TextBox
    Par archer dans le forum C#
    Réponses: 8
    Dernier message: 20/05/2008, 00h14
  2. Réponses: 5
    Dernier message: 19/05/2008, 10h31
  3. Controler des textBox dans des thread
    Par ramaro dans le forum Windows Forms
    Réponses: 5
    Dernier message: 25/04/2008, 14h21
  4. Textbox et Thread
    Par migutz dans le forum VB.NET
    Réponses: 1
    Dernier message: 22/04/2008, 12h46
  5. [vc++ 2005] acceder a un textbox a partir d un thread
    Par jerome86600 dans le forum VC++ .NET
    Réponses: 9
    Dernier message: 12/07/2006, 13h10

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