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 :

Plantage par Délégué sur Invoke() sur ListBox.


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    112
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 112
    Par défaut Plantage par Délégué sur Invoke() sur ListBox.
    Bonjour à tous*;

    Suis sous Seven avec 8GO Ram 1TO en DD …

    Je fais de la petite programmation sous Visual Studio 2008 Standart en C#.
    Dans un formulaire WindowsForm … entre autre une Listbox nommé lb_util où j'écris le déroulement des actions du programme. C'est là que se situe le problème.
    But du programme*: lancer des décompressions de fichiers. Chaque décompression est exécuté par un Thread différent.
    J'ai fait plusieurs essais*:
    1) Essai par Utilisation d'un tableau de Thread (t_thread[]) où chaque thread est lancé pour exécuter la méthode «* decompresser()*». Cette dernière méthode doit signaler son action par écriture dans la ListBox.

    morceaux de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                // lancement d'un thread
              Arg_decompress arg_decompress = new Arg_decompress(i, fichier);   // arguments
     
    t_thread[i] = new Thread(new ParameterizedThreadStart(this.decompresser));
                     t_thread[i].Start(arg_decompress);
    …............// methode pour decompresser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void... decompresser(objet data)
         {
         // déclaration et init d'un délégué de type Del_affich chargé d’écrire dans la ListBox (méthode Invoke() )
    // la méthode "del_method_aff_lb() est appelée par le délégué
         …...
              Del_affich del_af_lb = new Del_affich(del_method_aff_lb);
                  this.lb_util.Invoke(del_af_lb, txt);     // c'est là que ça plante grave 
          …....
            }
     
            // methode exécutée par le délégué sur la ListBox
     public void del_method_aff_lb(string t)
            {         …...this.lb_util.Items.Add(t);…......}
    Si je supprime l'appel du délégué (Invoke) le programme est OK.

    2) Essai par utilisation d'un pool de Thread (ThreadPool) au lieu du tableau de Thread
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ....     ThreadPool.QueueUserWorkItem(new WaitCallback( decompresser ), arg_decompress);   
       ....
    Le reste du code ne change pas.
    Chaque Thread du pool «*décompresse*» un fichier et doit écrire dans la ListBox via un délégué par Invoke(). Même punition, plantage au niveau du Invoke().

    3) Essai par utilisation d'un seul Thread*:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      ....   Thread    th = new Thread(new ParameterizedThreadStart(this.decompresser)); .....
    et là tout se passe correctement.

    Info supplémentaire*sur le plantage: aucune exception n'est levée … l'application ne répond pas
    Dans les deux premiers essais, si je supprime la ligne Invoke(délégué, texte à ecrire) tout est OK.
    Même en mode «*Deboggage*» aucune piste , … délégué bien initialisé …

    Grand merci à vous pour votre aide

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 067
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 067
    Par défaut
    tu peux essayer sinon de stocker ton résultat dans une variable et lancer un timer qui toutes les X seconde affectera la valeur de ton résultat à la Listbox

    après tu peux aller voir de ce coté pour l'utilisation des composants windowsforms avec les threads
    http://msdn.microsoft.com/fr-fr/libr...=VS.90%29.aspx

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    112
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 112
    Par défaut
    Merci Youtpout pour ta réponse;

    Je sais , j'ai mille idées pour contourner mon problème, mais j'aimerai qu'on me corrige et que je m' aperçoive de mon erreur.
    J'ai pourtant appliqué la règle d'or en la matière, à savoir que " lorsque un contrôle WinForm est accédé par un autre thread que celui qui l'a créé, (InvokeRequired == true, le thread appelant passe la main a un délégué invoqué par le contrôle appelé (controle.Invoke(délégué, arguments)."

    Dans mon cas, un seul thread ça marche ...
    Un thread d'un tableau ou d'un pool (ThreadPool) ça ne marche pas....

    J'aimerai comprendre...

    merci pour votre aide

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    112
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 112
    Par défaut
    Bonsoir;

    J'ai remodelé mon programme ... et déplacé le plantage.
    A présent l'accés à la ListBox est ok.
    Par contre , pour 4 Threads secondaires, j'ai créé un tableau de ManualResetEvent:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ManualResetEvent[] t_mre = new ManualResetEvent[4];
    En fin de chaque morceau de code exécuté par les threads secondaires, le signal est envoyé: exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    t_mre[0].Set(); ..... t_mre[3].Set();
    Et je fait attendre mon thread principal par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     WaitHandle.WaitAll(t_mre);
    Maintenant c'est là que ça palnte grave (appli ne répond pas)
    Le deboggage ne donne rien ....plantage complet.
    Comment receptionner les 4 signaux envoyés par le travail terminé des 4 threads secondaires en background ???

    Grand merci de votre aide.

  5. #5
    Membre chevronné Avatar de Jerede
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mai 2010
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mai 2010
    Messages : 271
    Par défaut
    Avec les bouts de code que tu nous donnes, on ira pas loin

    Sinon, une façon parmi beaucoup d'autres.

    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
     
            public void Decompresser(object i)
            {
                Thread.Sleep(1000 * int.Parse(i.ToString()));
                ChangeTextBox("Décompression " + i + " fini");
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                var tasks = new Task[5];
     
                for (int i = 0; i < 5; i++)
                    tasks[i] = Task.Factory.StartNew(Decompresser, i);
     
                Task.Factory.StartNew(() =>
                                          {
                                              Task.WaitAll(tasks);
                                              ChangeTextBox("Décompression terminée");
                                          });
            }
     
            private void ChangeTextBox(string text)
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke((Action<string>)ChangeTextBox, text);
                }
                else
                    textBox1.Text = text;
            }

  6. #6
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonsoir.

    Tout cela semble tout de même très curieux, je n'ai jamais eu de tels problèmes que ce soit avec Invoke ou les wait handle, à mon avis le problème est ailleurs (au hasard un vieux deadlock avec dans ton cas A qui invoque et attend B et B qui invoque et attend A - tente de remplacer des Invoke par des BeginInvoke). As-tu soigneusement vérifié la sortie de l'application (onglet "output" de VS) pour d'eventuelles mentions d'exceptions levées sur les threads workers avant qu'ils ne plantent ?

    Sinon, pour information, pour de nombreuses tâches courtes (moins de 250ms, si possible moins de 10ms) et dont les performances sont limitées par le CPU, le ThreadPool reste le meilleur moyen de faire (soit en utilisant directement le ThreadPool soit indirectement via les Tasks). En revanche, pour des tâches toujours nombreuses et courtes mais dont les performances sont cette fois limitées par l'I/O, le mieux est de lancer des traitements asynchrones (via FileStream.BeginRead) qui s'appuieront quant à eux sur le ThreadPool I/O du système d'exploitation.

    Dans les deux cas l'intérêt est que les deux ThreadPools (le pool managé ou le pool I/O de l'OS) sont capables d'ajuster automatiquement le nombre de threads pour maximiser les performances, en fonction de la charge CPU (plutôt CPU/RAM je crois) dans un cas et des accès I/O dans l'autre.

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

Discussions similaires

  1. Problème par rapport aux buffers sur proxy
    Par winnie82 dans le forum Réseau
    Réponses: 13
    Dernier message: 05/07/2006, 10h55
  2. Réponses: 8
    Dernier message: 19/06/2006, 15h31
  3. [MySQL] Problème par rapport au tutoriel sur le stockage des images en base
    Par dark_vidor dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 25/09/2005, 10h37
  4. Réponses: 1
    Dernier message: 28/08/2005, 07h30

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