Communication entre thread [Résolu]

olibara 670 Messages postés dimanche 16 décembre 2007Date d'inscription 11 mars 2010 Dernière intervention - 16 nov. 2008 à 09:53 - Dernière réponse : cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention
- 22 nov. 2008 à 23:25
Bonjour

Si quelqu'un se sent expert en Thread il pourra peut etre m'aider

L'ideal pour expliquer serait de pouvoir envoyer un bout de code malheureusement ca reste impossible sur ce Forum

Et le copie coller de code dans le message est totalement indigeste.
(N.B. Sauf erreur de ma part je pense que c'est un des rares forum qui ne gere pas la mise en forme ou l'envoi de code lié a un message)

Explication

Le but est de ne pas lancer un traitement lourd dans le thread de l'UI mais d'avoir une mise a jour de celui ci durant le process

Je lance donc le thread secondaire avec un threadpool et j'utilise deux event pour mettre a jour ma form

En mode debug ca marche tres bien
En mode release ca bloque apres plusieurs itérations !

Si quelqu'un se sent le courage d'essayer de comprendre avec moi on essayera de trouver la bonne maniere de communiquer le bout de code concerné

Merci beaucoup pour vos aides
Afficher la suite 

9 réponses

Répondre au sujet
cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention - 21 nov. 2008 à 09:27
+3
Utile
Bonjour,

Si j'ai bien tout compris au code, une DataTable est passée en référence aux threads (via DistMatrix ), qui y insèrent des lignes puis des cellules, en alertant la forme à chaque opération, qui elle essaye de présenter une DataView actualisée à chaque événement.
<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" /??>

Je ne suis pas certain qu'une DataTable soit ThreadSafe.
Il faudrait peut être mutualisé les d'insertions et de mise à jour de la DataTable depuis des méthodes de DistMatrix et y ajouter une protection par une section critique, de manière à être certain que 2 threads n'accèdent pas en même temps.

Il est fort possible qu'en mode debug l'environnement prenne en charge certaines situations de conflit d'accès.
Bien que je n'ai pas rencontré ce genre de problème en C# c'est un phénomène bien connu en C++ natif.

Pour ma part, dans ce genre de situation je laisse la forme maitresse gérer la table (insertion, mises à jour), et je ne demande aux threads que le calcul des données.

C# is amazing, enjoy it!
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_Robert33
cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention - 16 nov. 2008 à 10:02
0
Utile
Bonjour,

Sans voir le code il est difficile de répondre.
neamoins voici quelques pistes:
En .net les evenements ne sont pas "postés", mais executés au travers d'un delegate (le thread ne demande pas à la "form" de traiter  le message, mais le traite lui-même) le traitement est donc synchrone, il faut donc que le traitement de l'evenement soit court, dans le code de la "form" fais donc attention au evenements en cascade.
Si ton traitement bloque après quelques itérations, c'est sans doute un deadlock. fais attention aux classes et aux méthodes que tu utilises, l faut qu'elles soient toutes "thread safe" sinon mets en place des sémaphores ou des sections critiques.

en esperant t'avoir donné des info utiles.
++
C# is amazing, enjoy it!
Commenter la réponse de cs_Robert33
olibara 670 Messages postés dimanche 16 décembre 2007Date d'inscription 11 mars 2010 Dernière intervention - 16 nov. 2008 à 10:10
0
Utile
Merci Robert

Voici ce que je fais

Le process appelé contient deux boucles imbriquées qui remplissent une datatable de n x n
J'ai deux event : 1 pour l'ajout de row, 1 pour l'ajout de cellule
L'event ajout de cellule affiche un compteut dans la form appellante
L'event ajout de row fait un refresh du dgv qui possede la datatable en datasource

Voci la partie du code dans la form appellante

      DistMatrix dm = new DistMatrix();
      dm.VV = VV;
      dm.AddRow += new DistMatrix.StepRowDelegateHandler(Dist_StepRow);
      dm.AddCell += new DistMatrix.StepCellDelegateHandler(Dist_StepCell);
      ThreadPool.QueueUserWorkItem(new WaitCallback(Process), dm);
    }


    public delegate void StepCellDelegateHandler(int a, int b);
    public delegate void StepRowDelegateHandler(DataTable dt);


    // *****************************************************************************************
    void Process(Object DM)
    {
      DataTable dtn = ((DistMatrix)DM).getMatrix(dtAdr);
    }


    // *****************************************************************************************
    private void Dist_StepCell(int a, int b)
    {
      if (this.InvokeRequired)
      {
        try
        {
          this.Invoke(new StepCellDelegateHandler(StepCell), new object[] { a, b });
          return;
        }
        catch (Exception e)
        {
          MessageBox.Show(e.Message);
        }
      }
      else
      {
        this.StepCell(a, b);
      }
    }
    // *****************************************************************************************


    private void StepCell(int X, int Y)
    {
      if (X == -1)
      {
        MessageBox.Show("Call -1");
        btn_print.Enabled = true;
        btn_export.Enabled = true;
        toolStrip1.Enabled = true;
        return;
      }
      lbl_Progress.Text = string.Format("{0}-{1} / {2}", Y, X, dtAdr.Rows.Count);
      lbl_Progress.Refresh();
    }


    // *****************************************************************************************
    private void Dist_StepRow(DataTable dt)
    {
      if (this.InvokeRequired)
      {
        try
        {
          this.Invoke(new StepRowDelegateHandler(AddRow), new object[] { dt });
          return;
        }
        catch (Exception e)
        {
          MessageBox.Show("Row:" + e.Message);
        }
      }
      else
      {
        this.AddRow(dt);
      }
    }


    // *****************************************************************************************
    private void AddRow(DataTable Dt)
    {
      if (dgv_Dist.DataSource == null)
      {
        dgv_Dist.DataSource = Dt;
        foreach (DataGridViewColumn dgvc in dgv_Dist.Columns)
        {
          DataGridViewCellStyle style = new DataGridViewCellStyle();
          style.Format = "N2";
          style.Alignment = DataGridViewContentAlignment.MiddleRight;
          dgvc.DefaultCellStyle = style;
        }
      }
      dgv_Dist.Refresh();
    }
Commenter la réponse de olibara
leprov 1163 Messages postés vendredi 23 juillet 2004Date d'inscription 21 octobre 2010 Dernière intervention - 17 nov. 2008 à 10:03
0
Utile
Comme te l'as expliqué robert, les events sont executés dans le thread qui les appelles. De plus, la msdn spécifie que l'ihm ne devrais jamais etre modifiée au travers d'un autre thread que celui qui l'a créé. A mon avis, ton code doit vraiment pas bien fonctionner. Tu devrais essayer de voir du coté de l'objet backgroundworker qui va gérer le thread secondaire pour toi
Commenter la réponse de leprov
olibara 670 Messages postés dimanche 16 décembre 2007Date d'inscription 11 mars 2010 Dernière intervention - 17 nov. 2008 à 17:36
0
Utile
Salut

J'ai un problème en Release c'est un fait (en debug ca marche en "apparance" tres bien)

Mais je n'ai pas envie de jeter le BB avec l'eau du bain et j'aimerais comprendre ce que je peux ou dois faire dans le modele que j'ai utilisé pour permettre la mise a jour de mon DGV

Car si le Pavé qu'est le Backroundworker peut y arriver, il n'y a pas de raison qu'on ne puisse pas y arriver avec les outils de base !
Commenter la réponse de olibara
leprov 1163 Messages postés vendredi 23 juillet 2004Date d'inscription 21 octobre 2010 Dernière intervention - 18 nov. 2008 à 10:21
0
Utile
Avec les outils de base, tu devras regarder du coté du tuto sur le site concernant les opération cross thread
Commenter la réponse de leprov
olibara 670 Messages postés dimanche 16 décembre 2007Date d'inscription 11 mars 2010 Dernière intervention - 21 nov. 2008 à 09:37
0
Utile
Merci Robert

Ton explication m'aide a mieux comprendre le probleme
Je vais continuer a investiguer et tester !

Si j'y arrive je communique !
Commenter la réponse de olibara
olibara 670 Messages postés dimanche 16 décembre 2007Date d'inscription 11 mars 2010 Dernière intervention - 22 nov. 2008 à 22:45
0
Utile
Bonsoir Robert33

Voila j'ai réussi a faire tourner la chose proprement en suivant ta sugestion de separer les operatoions de calcul qui se font dans le thread secondaire et la mise a jour de la datatable, qui se fait dans le tread principal.

Je n'ai donc plus qu'un seul event qui renvoie l'absice, l'ordonée et la valeur a ajouter dans la datatable !

La derniere chose que j'ai du chipoter c'est pour traiter proprement la fin de l'execution du Thread.
Ca a ce moment seulement je voulais activer le print ou l'export du DGV créé

Pour faire cela j'ai encore du ajouter deux events et deux delegates !!
Voici ce que ca donne :

    /// <summary>
    /// Event et delegate de traitement fin de Thread
    /// </summary>
    public delegate void StopDistDelegateHandler();
    public event StopDistDelegateHandler enableBtn;


    public frmDist(DataTable dt)
    {
      dtAdr = dt;
      InitializeComponent();
    }


    public void ShowMatrix(bool VV)
    {
      DistMatrix dm = new DistMatrix();
      dm.VV = VV;
      dm.AddCell += new DistMatrix.StepCellDelegateHandler(Dist_StepCell);
      dtDist = dm.CreateTable(dtAdr);
      dgv_Dist.DataSource = dtDist;

      enableBtn += new StopDistDelegateHandler(EnableBtn);


      ThreadPool.QueueUserWorkItem(new WaitCallback(Process), dm);
    }


    public delegate void StepCellDelegateHandler(string x, string y, double dist);


    // *****************************************************************************************
    void Process(Object DM)
    {
      ((DistMatrix)DM).setMatrix(dtAdr);
      enableBtn();   // fin du Thread
    }
    // *****************************************************************************************
    private void EnableBtn()
    {
      if (this.InvokeRequired)
      {
        try
        {
          this.Invoke(new StopDistDelegateHandler(BtnEnable), new object[] {  });
          return;
        }
        catch (Exception e)
        {
          MessageBox.Show(e.Message);
        }
      }
      else
      {
        BtnEnable();
      }
    }
    // *****************************************************************************************
    private void BtnEnable()
    {
      btn_print.Enabled = true;
      btn_export.Enabled = true;
    }
Commenter la réponse de olibara
cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention - 22 nov. 2008 à 23:25
0
Utile
ça parait propre comme ça,
Content de t'avoir aidé.

C# is amazing, enjoy it!
Commenter la réponse de cs_Robert33

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.