Communication entre thread

Résolu
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 - 16 nov. 2008 à 09:53
cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 - 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

9 réponses

cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 33
21 nov. 2008 à 09:27
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!
3
cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 33
16 nov. 2008 à 10:02
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!
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
16 nov. 2008 à 10:10
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();
    }
0
leprov Messages postés 1160 Date d'inscription vendredi 23 juillet 2004 Statut Membre Dernière intervention 21 octobre 2010 17
17 nov. 2008 à 10:03
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
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
17 nov. 2008 à 17:36
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 !
0
leprov Messages postés 1160 Date d'inscription vendredi 23 juillet 2004 Statut Membre Dernière intervention 21 octobre 2010 17
18 nov. 2008 à 10:21
Avec les outils de base, tu devras regarder du coté du tuto sur le site concernant les opération cross thread
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
21 nov. 2008 à 09:37
Merci Robert

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

Si j'y arrive je communique !
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
22 nov. 2008 à 22:45
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;
    }
0
cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 33
22 nov. 2008 à 23:25
ça parait propre comme ça,
Content de t'avoir aidé.

C# is amazing, enjoy it!
0