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# Discussion :

Thread / Invoke et freeze


Sujet :

C#

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut Thread / Invoke et freeze
    Bonjour,

    J'essaye de lire des données provenant de mon hardware et de les afficher dans un label, le tout dans un timer.
    J'utilise System.Timers.Timer pour cela :
    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
    public partial class Form1 : Form {
         delegate void delegateDisplay();
         delegateDisplay dlgLbl;
     
         public Form1() {
              InitializeComponent();
              dlgLbl = new delegateDisplay(this.RefreshInfos);
         }
     
         private void RefreshInfos() {
     
              // récupère ici les infos du harware
              // cela prend environ 2,5 sec
              // ensuite j'affiche le résultat dans un label : 
              label1.Text = myHardware.DriverInfo.ToString()  // exemple
         }
     
         private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
     
              label1.Invoke(dlgLbl);
         }
    }
    Problème :
    Le temps de récupérer les infos du hardware prend environ 2,5 sec.
    Pendant ce temps, la fenêtre où j'affiche mon label freeze, ne répond pas, puisqu'elle communique avec le hardware pour récupérer les infos.
    Pourtant je croyais qu'en utilisant Invoke je passais par un thread et ça m'éviterait ce genre de problème d'attente ?

    Donc, comment pourrais-je modifier mon code pour que la fenêtre ne freeze pas ?

    Merci.

  2. #2
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    Utilise BeginInvoke au lieu de Invoke

    BeginInvoke réalise cet appel de manière asynchrone (le programme n'attend pas qu'elle soit terminée pour continuer son exécution), alors qu'Invoke le fait de manière synchrone (le programme bloque tant que la fonction n'est pas terminée)

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Ca ne change rien.
    Le problème est toujours là, il freeze pendant 2secondes le temps de récupérer les infos.

  4. #4
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    essaie:

    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
     
     
    void RefreshInfos()
            {
                if (label1.InvokeRequired)
                {
                    label1.BeginInvoke(new delegateDisplay(RefreshInfos));
                    // ou
                    label1.Invoke(new delegateDisplay(RefreshInfos));
                }
                else
                {
                    label1.Text = myHardware.DriverInfo.ToString();
                }
            }

  5. #5
    Membre émérite
    Avatar de azstar
    Homme Profil pro
    Architecte Technique BizTalk/.NET
    Inscrit en
    Juillet 2008
    Messages
    1 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Architecte Technique BizTalk/.NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 198
    Points : 2 424
    Points
    2 424
    Par défaut
    le mode asynchrone s'exécute dans un thread parallèle, ce qui nous permet une bon performance au niveau des traitements .

    tu peut soit utilise le mode asynchrone ou utilise un thread qui ce charge de récupère les infos de ton hardward ;pour éviter de faire le traitement dans un timer .
    car le timer s'exécute dans le thread principale de ton application y'a compri ton interface pour ce la vous avez un freeez dans votre form

  6. #6
    Membre à l'essai
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Points : 15
    Points
    15
    Par défaut
    Effectivement les timers de la classe System.Timers bloquent le thread principal. En utilisant les timers de System.Threading tu lances ton timer en arrière plan.

    Essaye si tu veux:

    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
     
     
    private System.Windows.Forms.Label m_label;
    private System.Threading.Timer m_myTimer;
    private bool pendule_lance = false;
     
    public void startPendule(System.Windows.Forms.Label label, int periode)
    		{
    			m_label = label; //le label que tu veux actualiser
     
    			TimerCallback timerDelegate = new TimerCallback(this.OnTimeEvent);
     
    			//Crée le timer qui lance le délégué 
    			m_myTimer = new System.Threading.Timer(timerDelegate, null, periode, periode);
    			pendule_lance = true;
    		}
     
    		private void OnTimeEvent(Object objet)
    		{
    			// récupère ici les infos du harware
                            // cela prend environ 2,5 sec
                            // ensuite j'affiche le résultat dans un label : 
                            m_label.Text = myHardware.DriverInfo.ToString();  // exemple
     
    		}
     
                    // à appeler dans le forme principale
    		public void stopPendule()
    		{
    			if (pendule_lance)
    			{
    				m_myTimer.Dispose();
    			}
    		}
    Ensuite tu lances startPendule dans ta forme principale, et le stopPendule dans le Dispose de la forme.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    chamamo > Merci, mais ca ne change rien car il ne rentre jamais dans le "if (label1.InvokeRequired)"..

    Ed.11 > Je vais tester merci.

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Citation Envoyé par Ed.11 Voir le message
    Effectivement les timers de la classe System.Timers bloquent le thread principal. En utilisant les timers de System.Threading tu lances ton timer en arrière plan.
    J'ai essayé ton code, mais j'ai une exception ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private void OnTimeEvent(Object objet)
    {
    // "Opération inter-threads non valide : le contrôle 'label1' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé."
             m_label.Text = "test";
    }
    Ci-joint mon code complet.

    Merci pour ton aide..
    Fichiers attachés Fichiers attachés

  9. #9
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private delegate void OnTimeEventDelegateHandler(Object objet);
    private OnTimeEventDelegateHandler OnTimeEventDelegate = new OnTimeEventDelegateHandler(OnTimeEvent);
     
    public void OnTimeEvent(Object objet)
            {
                this.BeginInvoke(this.OnTimeEventDelegate, new object[] {objet});
            }
     
    private void OnTime(Object objet)
    {
             m_label.Text = "test";
    }

  10. #10
    Membre à l'essai
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Points : 15
    Points
    15
    Par défaut
    J'ai ouvert ton code mais je n'ai pas bien compris ce que tu as fait ^^'

    Enfin voici une version viable (j'ai mis le Timer dans une autre classe pour plus de clarté, mais les noms ne sont pas très explicites).
    A partir de là, tu remplace et met le traitement que tu veux à la place du changement de texte dans le label =)

    Je n'ai pas mis le projet complet (sous Visual Studio 2003), car je ne suis pas sure que tu puisses l'ouvrir... donc j'ai mis le code source de la forme et de la classe.

    edit: (dis moi si ça marche car je ne pourrais plus tester d'ici lundi. Enfin, je ne sais pas si ça presse)
    Fichiers attachés Fichiers attachés

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Chamamo :
    Erreur: "Un initialiseur de champ ne peut pas faire référence au champ, à la méthode ou à la propriété non statique 'Form1.OnTimeEvent(object)'"
    à la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private OnTimeEventDelegateHandler OnTimeEventDelegate = new OnTimeEventDelegateHandler(OnTimeEvent);

    Merci Ed.11, je test ca

  12. #12
    Membre à l'essai
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Points : 15
    Points
    15
    Par défaut
    (j'ai retiré le zip car il était corrompu, voici un nouvel essai)
    Fichiers attachés Fichiers attachés

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Ed.11,
    J'ai mis tes 2 sources dans un nouveau projet et j'ai exactement la même exception "opération inter-threads" à la même ligne que précédemment.
    J'ai VS2008.
    Chez toi ca fonctionne bien ?!

    edit: je vais essayer avec ton .zip..

  14. #14
    Membre à l'essai
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Points : 15
    Points
    15
    Par défaut
    Oui, normalement tu trouveras l'exe en release dans le zip. C'est bizarre, t'as bien ajouté au projet?
    Je comprends pas :/

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Tres bizarre : avec ton .zip :
    les exécutables fonctionnent parfaitement,
    mais : dans visual studio, quand je lance le run (fleche verte) j'ai l'exception.

    VS réagit mal au multi-thread..?!

    Meci pour le code je vais tenter de récupérer mes infos maintenant !

  16. #16
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    dsl,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     private OnTimeEventDelegateHandler OnTimeEventDelegate;
    et dans ton constructeur, ou la ou tu initialises tes parameters tu fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    OnTimeEventDelegate = new OnTimeEventDelegateHandler(OnTimeEvent);

  17. #17
    Membre à l'essai
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Points : 15
    Points
    15
    Par défaut
    Bah c'est bizarre quand même que ça marche sur VS 2003 et pas sur le 2008.
    T'as ouvert en faisant "open project" ou juste les fichiers source?
    Ca se trouve si tu fait un nouveau projet, et que tu fait "add existing file", t'ajoute la class1 et tu rajoute les deux lignes de code dans la forme principale, peut être que ça marchera. (en ayant créer le label avant)

  18. #18
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    Je viens d'essayer sur un autre PC, VS2008, la meme chose!
    J'ai juste double cliqué sur ton .sln.

  19. #19
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Points : 132
    Points
    132
    Par défaut
    chamamo : merci, mais là c'est pire : la form n'affiche rien , freeze dès le lancement, "Form1 (ne répond pas)" en guise de titre..
    Est-ce que ca marche chez toi ? Si oui tu peux zipper ta solution ?
    Merci.

  20. #20
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    la je rentre chez moi, ça pourrait attendre je pense?

Discussions similaires

  1. [Débutant] Thread - Invoke
    Par taspai dans le forum VB.NET
    Réponses: 4
    Dernier message: 02/04/2014, 13h04
  2. Thread / Invoke / dans une autre classe
    Par totoz dans le forum VB.NET
    Réponses: 1
    Dernier message: 12/03/2009, 16h07
  3. Windows et Multi-Threading - Invoke
    Par zi_omnislasher dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 26/10/2007, 17h20
  4. Windows et Multi-Threading - Invoke
    Par zi_omnislasher dans le forum Windows
    Réponses: 1
    Dernier message: 26/10/2007, 10h13
  5. [C#][Thread][Invoke] petit problème de delegate
    Par clinic dans le forum Général Dotnet
    Réponses: 3
    Dernier message: 22/06/2007, 11h38

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