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 :

Opération inter thread non valide a ligne aprés le meme accès qui fonctionne


Sujet :

C#

  1. #1
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 956
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 956
    Points : 2 075
    Points
    2 075
    Par défaut Opération inter thread non valide a ligne aprés le meme accès qui fonctionne
    Bonjour

    Je calcule le contenu de courbes à afficher sur les série d'un MS chart sur une winform avec ceci
    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
    35
    36
    37
    38
    39
    40
    41
                try
                {
                    foreach (TreeNode ssNode in ssNodesChecked)
                    {
                        String NomSerie =  ssNode.FullPath;
     
                        chart1.Series.Add(NomSerie);                                 // Création de la série de donnée
                        chart1.Series[NomSerie].ChartType = SeriesChartType.Range;      // série de type range pour afficher le min et le max sur la plage de temps du pixel
                        chart1.Series[NomSerie].IsXValueIndexed = false;                // pour avoir les absices dans l'ordre et sans trous
                        chart1.Series[NomSerie].XValueType = ChartValueType.DateTime;   // axe X de type DateTime
     
                        Disu.Temporel MaTemporel = new Temporel(NbPixels, Properties.Settings.Default.CheminTravail + "\\" + ssNode.FullPath, DateMin, DateMax); //création d'un objet 
     
                        parallelTasks.Add(MaTemporel.CalculAsync(progressIndicator, ctsTemporel.Token).ContinueWith(tsk =>
                        { // Remplissage de la série
                            ctsTemporel.Token.ThrowIfCancellationRequested(); // Annulation si demandée par ailleurs
     
                            for (int i = 0; i < MaTemporel.NbpixelsFinal ; i++)
                            {
                                chart1.Series[NomSerie].Points.AddXY(MaTemporel.ResArray[i, 0], MaTemporel.ResArray[i, 1], MaTemporel.ResArray[i, 2]);
                            }
                        }, ctsTemporel.Token));
     
                    }
     
                    await Task.WhenAll(parallelTasks.ToArray());
                }
                catch (OperationCanceledException)
                {
                    toolStripStatusLabel1.Text = "Génération des courbes annulée !";
                    chart1.Series.Clear();
                    chart1.Invalidate();                    //force le redessin du chart
                    return;
                }
                catch (Exception ex)
                {
                    toolStripStatusLabel1.Text = "Erreur pendant la génération des courbes ! : " + ex.ToString();
                    chart1.Series.Clear();
                    chart1.Invalidate();                    //force le redessin du chart
                    return;
                }
    Cela fonctionne à merveille
    Maintenant, si j'ajoute des modification des séries ainsi
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
                try
                {
                    foreach (TreeNode ssNode in ssNodesChecked)
                    {
                        String NomSerie =  ssNode.FullPath;
     
                        chart1.Series.Add(NomSerie);                                 // Création de la série de donnée
                        chart1.Series[NomSerie].ChartType = SeriesChartType.Range;      // série de type range pour afficher le min et le max sur la plage de temps du pixel
                        chart1.Series[NomSerie].IsXValueIndexed = false;                // pour avoir les absices dans l'ordre et sans trous
                        chart1.Series[NomSerie].XValueType = ChartValueType.DateTime;   // axe X de type DateTime
     
                        Disu.Temporel MaTemporel = new Temporel(NbPixels, Properties.Settings.Default.CheminTravail + "\\" + ssNode.FullPath, DateMin, DateMax); //création d'un objet 
     
                        parallelTasks.Add(MaTemporel.CalculAsync(progressIndicator, ctsTemporel.Token).ContinueWith(tsk =>
                        { // Remplissage de la série
                            ctsTemporel.Token.ThrowIfCancellationRequested(); // Annulation si demandée par ailleurs
     
                            for (int i = 0; i < MaTemporel.NbpixelsFinal ; i++)
                            {
                                chart1.Series[NomSerie].Points.AddXY(MaTemporel.ResArray[i, 0], MaTemporel.ResArray[i, 1], MaTemporel.ResArray[i, 2]);
                            }
     
                            // Modif des markers suivant nombre de points affichés
                            if (MaTemporel.NbpixelsFinal < NbPixels / 4)
                            {
                                MessageBox.Show(chart1.Series[NomSerie].Points.Count.ToString());
                                chart1.Series[NomSerie].MarkerStyle = MarkerStyle.Square;
                                chart1.Series[NomSerie].MarkerColor = Color.Black;
                                chart1.Series[NomSerie].ToolTip = "#VALY - #VALX{G}";
                            }
                            else
                            {
                                chart1.Series[NomSerie].ToolTip = "";
                                chart1.Series[NomSerie].MarkerStyle = MarkerStyle.None;                  //## ca plante ici
                            }
     
                        }, ctsTemporel.Token));
     
                    }
     
                    await Task.WhenAll(parallelTasks.ToArray());
                }
                catch (OperationCanceledException)
                {
                    toolStripStatusLabel1.Text = "Génération des courbes annulée !";
                    chart1.Series.Clear();
                    chart1.Invalidate();                    //force le redessin du chart
                    return;
                }
                catch (Exception ex)
                {
                    toolStripStatusLabel1.Text = "Erreur pendant la génération des courbes ! : " + ex.ToString();
                    chart1.Series.Clear();
                    chart1.Invalidate();                    //force le redessin du chart
                    return;
                }
    ca plante à la ligne indiquée avec une exception "System.InvalidOperationException" "Opération inter-threads non valide*: le contrôle 'chart1' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé."

    Là où je ne comprends plus rien c'est que ce code qui plante est juste aprés, dans la même portée que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (int i = 0; i < MaTemporel.NbpixelsFinal ; i++)
    {
     chart1.Series[NomSerie].Points.AddXY(MaTemporel.ResArray[i, 0], MaTemporel.ResArray[i, 1], MaTemporel.ResArray[i, 2]);
    }
    qui fonctionne pourtant très bien sans exception...

    Comment une ligne peut elle être sur le bon thread et la suivante, dans la même portée, non ?
    Le truc c'est que je ne vois pas où placer mon code autre-part...

    Merci par avance
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  2. #2
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Bonjour, à mon avis la collection Points ne fait pas de vérification de l'identité du thread, tout simplement, et tu coures le risque d'un bogue aléatoire et silencieux. Ou peut-être cette collection a t-elle été conçue pour un usage concurrent, auquel cas tout va bien et iol est normal qu'il n'y ait pas de vérification.

    Quoi qu'il en soit, la bonne solution est de détacher les opérations UI pour les placer après ton "await", puisque ce dernier te ramène sur le thread UI. Autrement dit vire ton ContinueWith et place son code après ton "await".

  3. #3
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 956
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 956
    Points : 2 075
    Points
    2 075
    Par défaut
    argh c'est pas bon ça le coup des bugs silencieux...

    Mais comment puis-je retirer ça du ContinueWith ?
    J'ai besoin de la portée sur "NomSerie" et l'objet "MaTemporel"

    Je n'y ai plus accès si je n'ai pas le ContinueWith

    Merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  4. #4
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    En gros il te faut une structure de données dans laquelle tu stockeras tous tes objets "temporel" tout en les y associant au nom de série adéquat (soit en le créant un champ sur Temporel, soit en ayant un dictionnaire).

    Sinon tu peux aussi, plus simplement (quoique plus compliqué à comprendre à mon avis), utiliser une autre variante de ContinueWith où tu préciseras le contexte de synchronisation à utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    .ContinueWith(tsk => ...,     TaskScheduler.FromCurrentSynchronizationContext());
    Un contexte de synchronisation définit comment communiquer avec un thread, en l’occurrence celui de l'UI. Tu fournis donc ainsi un agenceur (scheduler) qui affectera tes continuations au thread UI via le contexte de synchronisation vers ce dernier. Donc tes continuations seront exécutées sur l'UI.

  5. #5
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 956
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 956
    Points : 2 075
    Points
    2 075
    Par défaut
    Non seulement cette solution est très simple mais je ne la trouve pas si compliquée que ça
    Le fait de spécifier dans quel thread on veut que la continuation soit exécutée est plein de bon sens.

    Cela semble corriger mon problème et ne pas en introduire d'autre, j'ai mis ça à la place du cts.token qu'il y avait à la fin du ContinueWith et qui ne servait pas à grand chose.

    et si en plus ça peut m'éviter des bug aléatoires et silencieux...

    Merci beaucoup
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

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

Discussions similaires

  1. [Débutant] Opération inter-threads non valide
    Par Conscious Ape dans le forum C#
    Réponses: 6
    Dernier message: 12/02/2013, 14h59
  2. Opération inter-threads non valide VB.NET
    Par airemax dans le forum VB.NET
    Réponses: 2
    Dernier message: 01/05/2011, 11h51
  3. Accès inter-threads non valide et BitmapImage
    Par Louis745 dans le forum Silverlight
    Réponses: 6
    Dernier message: 31/10/2010, 16h16
  4. Opération inter-threads non valide
    Par nakk01 dans le forum Windows Forms
    Réponses: 5
    Dernier message: 26/05/2009, 01h43
  5. Erreur : Opération inter-threads non valide
    Par cadeau dans le forum C++/CLI
    Réponses: 1
    Dernier message: 12/12/2006, 09h07

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