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 :

Winform : Parallelisme => Interaction avec les composants graphiques


Sujet :

C#

  1. #1
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut Winform : Parallelisme => Interaction avec les composants graphiques
    Bonjour @ tous,

    Je me met au parallélisme, et j'ai un traitement en winform qui charge des feuilles Excel dans des Hashtable.
    L'opération se fait plusieurs fois, j'ai donc décidé d'utiliser le parallélisme.
    Du coup, il me faut une progressBar par traitement. J'ai donc décidé (pour tester) de les empiler dans un composant texte qui prends une bonne partie de mon interface.
    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
                Hashtable htUd = null;
                Hashtable htCpm = null;
                Hashtable htItem = null;
                Hashtable htSpm = null;
                Hashtable htSol = null;
                Hashtable htEIPC = null;
                Hashtable htSbA = null;
                Hashtable htSbB = null;
                Parallel.Invoke(
                    () => { htUd = GetListe(txtFicXlsUd.Text, txtXlsFllUd.Text, txtXlsRefUD.Text, txtXlsLibUD.Text, txtXlsLn1UD.Text, "Lecture de la liste 1"); },
                    () => { htCpm = GetListe(txtFicXlsCPM.Text, txtXlsFllCPM.Text, txtXlsRefCPM.Text, txtXlsLibCPM.Text, txtXlsLn1CPM.Text, "Lecture de la liste 2"); },
                    () => { htItem = GetListe(txtFicXlsITEM.Text, txtXlsFllITEM.Text, txtXlsRefITEM.Text, txtXlsLibITEM.Text, txtXlsLn1ITEM.Text, "Lecture de la liste 3"); },
                    () => { htSpm = GetListe(txtFicXlsSPM.Text, txtXlsFllSPM.Text, txtXlsRefSPM.Text, txtXlsLibSPM.Text, txtXlsLn1SPM.Text, "Lecture de la liste des 4"); },
                    () => { htSol = GetListe(txtFicXlsSOL.Text, txtXlsFllSOL.Text, txtXlsRefSOL.Text, txtXlsLibSOL.Text, txtXlsLn1SOL.Text, "Lecture de la liste des 5"); },
                    () => { htEIPC = GetListe(txtFicXlsEIPCA.Text, txtXlsFllEIPCA.Text, txtXlsRefEIPCA.Text, txtXlsLibEIPCA.Text, txtXlsLn1EIPCA.Text, "Lecture de la liste 6"); },
                    () => { htSbA = GetListe(txtFicXlsSBA.Text, txtXlsFllSBA.Text, txtXlsRefSBA.Text, txtXlsLibSBA.Text, txtXlsLn1SBA.Text, "Lecture de la liste des 7"); },
                    () => { htSbB = GetListe(txtFicXlsSBB.Text, txtXlsFllSBB.Text, txtXlsRefSBB.Text, txtXlsLibSBB.Text, txtXlsLn1SBB.Text, "Lecture de la liste des 8"); }
                ); // */
     
            private Hashtable GetListe(string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId="") {
                Hashtable ret = new Hashtable();
                int tmp = 0;
                if (!string.IsNullOrEmpty(ficXls.Trim()) && (File.Exists(ficXls)) && (int.TryParse(xlsLigne1, out tmp))) {
                    UtilsExcel ue = new UtilsExcel();
                    tssLabel.Text = texte;
                    ProgressBar pb = new ProgressBar();
                    pb.Name = Guid.NewGuid().ToString();
                    if (txtInfos.InvokeRequired) { // Gérer les accès concurentiels.
                        txtInfos.Invoke(new AddControl(CtlAddControl), txtInfos, pb);
                    } else
                        pb.Parent = txtInfos;
                    Application.DoEvents();
                    pb.Dock = DockStyle.Top;
                    pb.BringToFront(); // */
                    ret = ue.GetListe(ficXls, xlsFeuille, xlsColId, xlsColLib, tmp, ref pb, regexId); //tssPbMain
                    pb.Dispose();
                    if (string.IsNullOrEmpty(ue.msgErr)) {
                        txtInfos.Text += "OK. " + tssLabel.Text + ". " + ret.Count + " éléments intégrés." + Environment.NewLine + ue.msgInfo;
                    } else
                        txtInfos.Text += "KO. " + tssLabel.Text + ". " + ue.msgErr + Environment.NewLine;
                } // */
                return ret;
            }
     
            private delegate void AddControl(Control ctlParent, Control ctlEnfant); // Modèle de fonction (prototype) pour l'instanciation.
            private static void CtlAddControl(Control ctlParent, Control ctlEnfant) {
                Application.DoEvents();
                ctlEnfant.Parent = ctlParent;
            }
    Seulement, ça ne fonctionne pas (si je suis en synchrone, ça fonctionne).
    Les progressbar n'apparaissent pas... Je ne vois même pas Excel se lancer.

    Qu'est ce que je n'ai pas fait comme il faut ?

    [EDIT] : En fait, il fait bien toutes les actions, mais il doit bloquer quelque part car je vois tous les libellés passer, mais le traitement ne se termine jamais.

    Merci d'avance.
    David.

  2. #2
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Le souci principal est que Parallel.Invoke est un appel bloquant/synchrone qui ne revient que quand toutes les tâches sont finies.
    Donc tu bloques ton thread UI qui ne peut plus traiter les autres évènements dont ceux de repaint.
    C'est pourquoi tu es obligé de bidouiller avec Application.DoEvents.

    Quick-and-dirty fix :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Task.Factory.StartNew(() => Parallel.Invoke(...));
    Après je vois un peu de magie : des accès à txtInfos non protégés qui n'explosent pas!
    Je ne suis pas un expert WinForms mais ça ne devrait être possible que si tu es déjà sur le thread UI ce qui à priori n'est pas le cas...
    Mystère et boule de gomme...
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  3. #3
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    Bonjour Pragmateek,

    L'accès à txtInfo n'explose pas car il écrit juste une fois à la fin du traitement et qu'aucun ne tombe en même temps.
    Mais tu as raison, ce n'est pas propre... Une fois que mon parallel fonctionnera, je mettrait tout ça d'équerre.

    J'ai bien vu un progressBar s'afficher avec ta solution, mais j'ai quelques erreurs.

    En premier lieu, sur "pb.Dock = DockStyle.Top" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Opération inter-threads non valide : le contrôle 'acc31830-91b5-4d91-ae8b-dd046046b5a0' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.
    J'ai du mal à le comprendre car le composant est completement interne au thread.

    Ensuite, le Task.Factory.StartNew lance bien les fonctions,, mais elle n'ont pas encore démarrées que la suite de mon code est executé avant que mes Hashtable aient eu le temps de se remplir.
    Du coup Ils sont null et mon traitement est quaduque.
    Il faudrait que la suite de mon code ne se déclenche que lorsque toutes les taches sont finies.
    David.

  4. #4
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Citation Envoyé par dacid Voir le message
    L'accès à txtInfo n'explose pas car il écrit juste une fois à la fin du traitement et qu'aucun ne tombe en même temps.
    Ce n'est pas la synchronisation qui m'interpelle mais l'absence d'exception cross-thread.

    Citation Envoyé par dacid Voir le message
    En premier lieu, sur "pb.Dock = DockStyle.Top" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Opération inter-threads non valide : le contrôle 'acc31830-91b5-4d91-ae8b-dd046046b5a0' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.
    J'ai du mal à le comprendre car le composant est completement interne au thread.
    Oui bizarre, pour le coup je m'attendrais plus à une erreur sur la nature STA du thread...

    Citation Envoyé par dacid Voir le message
    Ensuite, le Task.Factory.StartNew lance bien les fonctions,, mais elle n'ont pas encore démarrées que la suite de mon code est executé avant que mes Hashtable aient eu le temps de se remplir.
    Du coup Ils sont null et mon traitement est quaduque.
    Il faudrait que la suite de mon code ne se déclenche que lorsque toutes les taches sont finies.
    C'est normal en effet, il suffit juste d'ajouter le traitement s'exécutant après ta récupération de données au sein de la lambda du StartNew.
    L'idée est de libérer le thread UI pendant la récupération afin que ton interface reste réactive.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  5. #5
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    J'ai oté les choses qui pouvaient faire des problèmes cross-thread.
    Et Suite aux exemples de Krosoft, j'ai mis ma fonction en statique.
    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
            private delegate Hashtable GetListeDelg(Form frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId = "");
            private static Hashtable GetListe(frmMain frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId="") {
                /*if (InvokeRequired) { // Gérer les accès concurentiels.
                    return (Hashtable)Invoke(new GetListeDelg(GetListe), frm, ficXls, xlsFeuille, xlsColId, xlsColLib, xlsLigne1, texte, regexId);
                } // */
                Hashtable ret = new Hashtable();
                int tmp = 0;
                if (!string.IsNullOrEmpty(ficXls.Trim()) && (File.Exists(ficXls)) && (int.TryParse(xlsLigne1, out tmp))) {
                    try {
                        UtilsExcel ue = new UtilsExcel();
                        /*if (frm.tssLabel.GetCurrentParent().InvokeRequired) { // Gérer les accès concurentiels.
                            frm.tssLabel.GetCurrentParent().Invoke(new UtilsControls.setControlStr(UtilsControls.ctrlAddText), frm.tssLabel, texte);
                        } else
                            frm.tssLabel.Text += texte; // */
                        using (var pb = new ProgressBar()) {
                            pb.Name = "pb"+Guid.NewGuid().ToString().Substring(0, 8).Replace("-", "");
                            if (frm.txtInfos.InvokeRequired) { // Gérer les accès concurentiels.
                                frm.txtInfos.Invoke(new UtilsControls.AddControl(UtilsControls.CtlAddControl), frm.txtInfos, pb);
                            } else
                                pb.Parent = frm.txtInfos;
                            Application.DoEvents();
                            pb.Dock = DockStyle.Top;
                            ret = ue.GetListe(ficXls, xlsFeuille, xlsColId, xlsColLib, tmp, pb, regexId); //tssPbMain
                        }
                        string msg = (string.IsNullOrEmpty(ue.msgErr)) ? 
                            "OK. " + frm.tssLabel.Text + ". " + ret.Count + " éléments intégrés." + Environment.NewLine + ue.msgInfo:
                            "KO. " + frm.tssLabel.Text + ". " + ue.msgErr + Environment.NewLine;
                            if (frm.txtInfos.InvokeRequired) { // Gérer les accès concurentiels.
                                frm.txtInfos.Invoke(new UtilsControls.setControlStr(UtilsControls.ctrlAddText), frm.txtInfos, msg);
                            } else
                                frm.txtInfos.Text += msg;
                    } catch (Exception ex) {
                    }
                } // */
                return ret;
            }
     
            static Hashtable htUd = null;
            static Hashtable htCpm = null;
            static Hashtable htItem = null;
            static Hashtable htSpm = null;
            static Hashtable htSol = null;
            static Hashtable htEIPC = null;
            static Hashtable htSbA = null;
            static Hashtable htSbB = null;
            private void btnVal_Click(object sender, EventArgs e) {
                canChangePc = true;
                txtInfos.Text = "";
                tcMain.SelectedIndex = tcMain.SelectedIndex + 1;
                Parallel.Invoke(new ParallelOptions { },  // Task.Factory.StartNew(() => 
                    () => { htUd = GetListe(this, txtFicXlsUd.Text, txtXlsFllUd.Text, txtXlsRefUD.Text, txtXlsLibUD.Text, txtXlsLn1UD.Text, "Lecture de la liste 1"},                 () => { htCpm = GetListe(this, txtFicXlsCPM.Text, txtXlsFllCPM.Text, txtXlsRefCPM.Text, txtXlsLibCPM.Text, txtXlsLn1CPM.Text, "Lecture de la liste 2"); },
                    () => { htItem = GetListe(this, txtFicXlsITEM.Text, txtXlsFllITEM.Text, txtXlsRefITEM.Text, txtXlsLibITEM.Text, txtXlsLn1ITEM.Text, "Lecture de la liste 3"); },
                    () => { htSpm = GetListe(this, txtFicXlsSPM.Text, txtXlsFllSPM.Text, txtXlsRefSPM.Text, txtXlsLibSPM.Text, txtXlsLn1SPM.Text, "Lecture de la liste 4"); },
                    () => { htSol = GetListe(this, txtFicXlsSOL.Text, txtXlsFllSOL.Text, txtXlsRefSOL.Text, txtXlsLibSOL.Text, txtXlsLn1SOL.Text, "Lecture de la liste 5"); },
                    () => { htEIPC = GetListe(this, txtFicXlsEIPCA.Text, txtXlsFllEIPCA.Text, txtXlsRefEIPCA.Text, txtXlsLibEIPCA.Text, txtXlsLn1EIPCA.Text, "Lecture de la liste 6"); },
                    () => { htSbA = GetListe(this, txtFicXlsSBA.Text, txtXlsFllSBA.Text, txtXlsRefSBA.Text, txtXlsLibSBA.Text, txtXlsLn1SBA.Text, "Lecture de la liste des 7"); },
                    () => { htSbB = GetListe(this, txtFicXlsSBB.Text, txtXlsFllSBB.Text, txtXlsRefSBB.Text, txtXlsLibSBB.Text, txtXlsLn1SBB.Text, "Lecture de la liste des 8"); }
                ); // */
                tssLabel.Text = "Traitement des XML";
                EMS_CMF56.Traite(txtChemRepUd.Text, txtFicXsd.Text, htUd, htCpm, htItem, htSpm, htSol, htEIPC, htSbA, htSbB, txtInfos, tssPbMain.ProgressBar);
                tssLabel.Text = "Traitement terminé";
            }
     
        class UtilsControls {
     
            public delegate void AddControl(Control ctlParent, Control ctlEnfant); // Modèle de fonction (prototype) pour l'instanciation.
            public static void CtlAddControl(Control ctlParent, Control ctlEnfant) {
                try {
                    ctlEnfant.Parent = ctlParent;
                } catch (Exception ex) {
                    Log.LogWriter.Instance.WriteException(ex);
                    Log.LogWriter.Instance.FlushLog();
                }
            }
     
            public delegate void setControlStr(Control ctl, string str); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlAddText(Control ctl, string str) {
                Application.DoEvents();
                ctl.Text += str;
            }
     
            public delegate void setPbInc(ProgressBar ctl, int cmp, int total);
            public static void ProgBarInc(ProgressBar pb, int cmp, int total) { // ToolStripProgressBar
                pb.Value = Math.Min(((int)(((double)cmp / total) * 100)), 100);
            }
     
        }
    Mais ça ne fonctionne toujours pas. Le traitement se fait bien, mais le PB ne s'affiche pas.
    Le concept de la class paralell semblait pourtant d'une extreme simplicité.
    David.

  6. #6
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    J'ai l'impression de le toucher du bout des doigts.
    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
            private delegate Hashtable GetListeDelg(Form frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId = "");
            private static Hashtable GetListe(frmMain frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId="") {
                /*if (InvokeRequired) { // Gérer les accès concurentiels.
                    return (Hashtable)Invoke(new GetListeDelg(GetListe), frm, ficXls, xlsFeuille, xlsColId, xlsColLib, xlsLigne1, texte, regexId);
                } // */
                Hashtable ret = new Hashtable();
                int tmp = 0;
                if (!string.IsNullOrEmpty(ficXls.Trim()) && (File.Exists(ficXls)) && (int.TryParse(xlsLigne1, out tmp))) {
                    //try {
                        UtilsExcel ue = new UtilsExcel();
                        /*if (frm.tssLabel.GetCurrentParent().InvokeRequired) { // Gérer les accès concurentiels.
                            frm.tssLabel.GetCurrentParent().Invoke(new UtilsControls.setControlStr(UtilsControls.ctrlAddText), frm.tssLabel, texte);
                        } else
                            frm.tssLabel.Text += texte; // */
                        using (var pb = new ProgressBar()) {
                            pb.Name = "pb" + Guid.NewGuid().ToString().Substring(0, 8).Replace("-", "");
                            if (frm.txtInfos.InvokeRequired) { // Gérer les accès concurentiels.
                                frm.txtInfos.Invoke(new UtilsControls.AddControl(UtilsControls.CtlAddControl), frm.txtInfos, pb);
                            } else
                                pb.Parent = frm.txtInfos;
                            Application.DoEvents();
                            if (pb.InvokeRequired) { // Gérer les accès concurentiels.
                                pb.Invoke(new UtilsControls.setControlDock(UtilsControls.ctrlDock), pb, DockStyle.Top);
                            } else
                                pb.Dock = DockStyle.Top;
                            ret = ue.GetListe(ficXls, xlsFeuille, xlsColId, xlsColLib, tmp, pb, regexId); //tssPbMain
                        }
                        string msg = (string.IsNullOrEmpty(ue.msgErr)) ? 
                            "OK. " + frm.tssLabel.Text + ". " + ret.Count + " éléments intégrés." + Environment.NewLine + ue.msgInfo:
                            "KO. " + frm.tssLabel.Text + ". " + ue.msgErr + Environment.NewLine;
                            if (frm.txtInfos.InvokeRequired) { // Gérer les accès concurentiels.
                                frm.txtInfos.Invoke(new UtilsControls.setControlStr(UtilsControls.ctrlAddText), frm.txtInfos, msg);
                            } else
                                frm.txtInfos.Text += msg;
                    /*} catch (Exception ex) {
                        Log.LogWriter.Instance.WriteException(ex);
                        Log.LogWriter.Instance.FlushLog();
                    } // */
                } // */
                return ret;
            }
     
            static Hashtable htUd = null;
            static Hashtable htCpm = null;
            static Hashtable htItem = null;
            static Hashtable htSpm = null;
            static Hashtable htSol = null;
            static Hashtable htEIPC = null;
            static Hashtable htSbA = null;
            static Hashtable htSbB = null;
            private void btnVal_Click(object sender, EventArgs e) {
                canChangePc = true;
                txtInfos.Text = "";
                tcMain.SelectedIndex = tcMain.SelectedIndex + 1;
                int nbCoeurs = 2;
                int.TryParse(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"), out nbCoeurs);
                Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = nbCoeurs },  // Task.Factory.StartNew(() => 
                    () => { htUd = GetListe(this, txtFicXlsUd.Text, txtXlsFllUd.Text, txtXlsRefUD.Text, txtXlsLibUD.Text, txtXlsLn1UD.Text, "Lecture de la liste 0"); }, 
                    () => { htCpm = GetListe(this, txtFicXlsCPM.Text, txtXlsFllCPM.Text, txtXlsRefCPM.Text, txtXlsLibCPM.Text, txtXlsLn1CPM.Text, "Lecture de la liste 1"); },
                    () => { htItem = GetListe(this, txtFicXlsITEM.Text, txtXlsFllITEM.Text, txtXlsRefITEM.Text, txtXlsLibITEM.Text, txtXlsLn1ITEM.Text, "Lecture de la liste 2"); },
                    () => { htSpm = GetListe(this, txtFicXlsSPM.Text, txtXlsFllSPM.Text, txtXlsRefSPM.Text, txtXlsLibSPM.Text, txtXlsLn1SPM.Text, "Lecture de la liste 3"); },
                    () => { htSol = GetListe(this, txtFicXlsSOL.Text, txtXlsFllSOL.Text, txtXlsRefSOL.Text, txtXlsLibSOL.Text, txtXlsLn1SOL.Text, "Lecture de la liste 4"); },
                    () => { htEIPC = GetListe(this, txtFicXlsEIPCA.Text, txtXlsFllEIPCA.Text, txtXlsRefEIPCA.Text, txtXlsLibEIPCA.Text, txtXlsLn1EIPCA.Text, "Lecture de la liste 5"); },
                    () => { htSbA = GetListe(this, txtFicXlsSBA.Text, txtXlsFllSBA.Text, txtXlsRefSBA.Text, txtXlsLibSBA.Text, txtXlsLn1SBA.Text, "Lecture de la liste des 6"); },
                    () => { htSbB = GetListe(this, txtFicXlsSBB.Text, txtXlsFllSBB.Text, txtXlsRefSBB.Text, txtXlsLibSBB.Text, txtXlsLn1SBB.Text, "Lecture de la liste des 7"); }
                ); // */
                tssLabel.Text = "Traitement des XML";
                Traite(txtChemRepUd.Text, txtFicXsd.Text, htUd, htCpm, htItem, htSpm, htSol, htEIPC, htSbA, htSbB, txtInfos, tssPbMain.ProgressBar);
                tssLabel.Text = "Traitement terminé";
            }
        class UtilsControls {
     
            public delegate void AddControl(Control ctlParent, Control ctlEnfant); // Modèle de fonction (prototype) pour l'instanciation.
            public static void CtlAddControl(Control ctlParent, Control ctlEnfant) {
                try {
                    ctlEnfant.Parent = ctlParent;
                } catch (Exception ex) {
                    Log.LogWriter.Instance.WriteException(ex);
                    Log.LogWriter.Instance.FlushLog();
                }
            }
     
            public delegate void setControlDock(Control ctl, DockStyle ds); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlDock(Control ctl, DockStyle ds) {
                ctl.Dock = ds;
            }
     
            public delegate void setControlStr(Control ctl, string str); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlAddText(Control ctl, string str) {
                Application.DoEvents();
                ctl.Text += str;
            }
     
            public delegate void setPbInc(ProgressBar ctl, int cmp, int total);
            public static void ProgBarInc(ProgressBar pb, int cmp, int total) { // ToolStripProgressBar
                pb.Value = Math.Min(((int)(((double)cmp / total) * 100)), 100);
            }
     
        }
    Les PB s'affichent bien, mais j'ai une erreur qui est positionnée à la fin du "using (var pb = new ProgressBar()) ".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Exception: Opération inter-threads non valide*: le contrôle 'pbf057b4da' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.
    Je pense que c'est parce que les PB créés ont tous les même parent.

    Comment résoudre ça ?
    David.

  7. #7
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Pourquoi as-tu toujours besoin du Application.DoEvents ?

    Quand tu dis "à la fin" c'est au niveau de l'accolade fermante ?
    Si c'est le cas c'est l'appel implicite à Dispose par le bloc using qui peut faire péter.

    Sinon le Parallel.Invoke ne me semble pas en effet être l'outil idoine.
    Vu que tu utilises des ProgressBars des BackgroundWorkers pourraient bien faire l'affaire...
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  8. #8
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    J'ai oté le DoEvent().

    Oui, c'est l'accolade fermante, je pense en effet que c'est le dispose, mais je ne me l'explique pas.

    BackgroundWorkers ? Je ne connais pas, je vais jeter un oeil.

    Merci.
    David.

  9. #9
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Dans ce cas tu peux remplacer le using par un try/finally :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var pb = new ProgressBar();
    try
    {
        ...
    }
    finally
    {
        pb.Dispose();
    }
    BackgroundWorker comme son nom l'indique c'est pour l'exécution de tâches en arrière plan.
    Il supporte notamment la notification de l'avancement, donc pratique pour se lier à une ProgressBar.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  10. #10
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    J'ai un truc qui marche presque. Les 4 barres se lancent bien et tout fonctionne bien, mais il refuse de sortir de l'invoke.
    La dernière barre est figée à 20% et il ne continue pas le script.
    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
            private delegate Hashtable GetListeDelg(Form frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId = "");
            private static Hashtable GetListe(frmMain frm, string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId="") {
                /*if (InvokeRequired) { // Gérer les accès concurentiels.
                    return (Hashtable)Invoke(new GetListeDelg(GetListe), frm, ficXls, xlsFeuille, xlsColId, xlsColLib, xlsLigne1, texte, regexId);
                } // */
                Hashtable ret = new Hashtable();
                int tmp = 0;
                if (!string.IsNullOrEmpty(ficXls.Trim()) && (File.Exists(ficXls)) && (int.TryParse(xlsLigne1, out tmp))) {
                    //try {
                        UtilsExcel ue = new UtilsExcel();
                        //UtilsControls.ctrlAddText(frm.tssLabel, texte);
                        //System.Threading.Thread.BeginCriticalRegion();
                        var pb = new ProgressBar();
                        pb.Name = "pb" + Guid.NewGuid().ToString().Substring(0, 8).Replace("-", "");
                        UtilsControls.CtlAddControl(frm.txtInfos, pb);
                        UtilsControls.ctrlDock(pb, DockStyle.Top);
                        ret = ue.GetListe(ficXls, xlsFeuille, xlsColId, xlsColLib, tmp, pb, regexId); //tssPbMain
                        if (pb.InvokeRequired) { // Gérer les accès concurentiels.
                            pb.Invoke(new UtilsControls.DisposeControlDock(UtilsControls.ctrlDispose), pb);
                        } else
                            pb.Dispose();
                        //System.Threading.Thread.EndCriticalRegion();
                        string msg = (string.IsNullOrEmpty(ue.msgErr)) ? 
                            "OK. " + frm.tssLabel.Text + ". " + ret.Count + " éléments intégrés." + Environment.NewLine + ue.msgInfo:
                            "KO. " + frm.tssLabel.Text + ". " + ue.msgErr + Environment.NewLine;
                        UtilsControls.ctrlAddText(frm.txtInfos, msg);
                    /*} catch (Exception ex) {
                        Log.LogWriter.Instance.WriteException(ex);
                        Log.LogWriter.Instance.FlushLog();
                    } // */
                } // */
                return ret;
            }
     
            static Hashtable htUd = null;
            static Hashtable htCpm = null;
            static Hashtable htItem = null;
            static Hashtable htSpm = null;
            static Hashtable htSol = null;
            static Hashtable htEIPC = null;
            static Hashtable htSbA = null;
            static Hashtable htSbB = null;
            private void btnVal_Click(object sender, EventArgs e) {
                canChangePc = true;
                txtInfos.Text = "";
                tcMain.SelectedIndex = tcMain.SelectedIndex + 1;
                int nbCoeurs = 2;
                int.TryParse(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"), out nbCoeurs);
                Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = nbCoeurs },  // Task.Factory.StartNew(() => 
                    () => { htUd = GetListe(this, txtFicXlsUd.Text, txtXlsFllUd.Text, txtXlsRefUD.Text, txtXlsLibUD.Text, txtXlsLn1UD.Text, "Lecture de la liste 1"); },
                    () => { htCpm = GetListe(this, txtFicXlsCPM.Text, txtXlsFllCPM.Text, txtXlsRefCPM.Text, txtXlsLibCPM.Text, txtXlsLn1CPM.Text, "Lecture de la liste 2"); },
                    () => { htItem = GetListe(this, txtFicXlsITEM.Text, txtXlsFllITEM.Text, txtXlsRefITEM.Text, txtXlsLibITEM.Text, txtXlsLn1ITEM.Text, "Lecture de la liste 3"); },
                    () => { htSpm = GetListe(this, txtFicXlsSPM.Text, txtXlsFllSPM.Text, txtXlsRefSPM.Text, txtXlsLibSPM.Text, txtXlsLn1SPM.Text, "Lecture de la liste 4"); },
                    () => { htSol = GetListe(this, txtFicXlsSOL.Text, txtXlsFllSOL.Text, txtXlsRefSOL.Text, txtXlsLibSOL.Text, txtXlsLn1SOL.Text, "Lecture de la liste 5"); },
                    () => { htEIPC = GetListe(this, txtFicXlsEIPCA.Text, txtXlsFllEIPCA.Text, txtXlsRefEIPCA.Text, txtXlsLibEIPCA.Text, txtXlsLn1EIPCA.Text, "Lecture de la liste 6"); },
                    () => { htSbA = GetListe(this, txtFicXlsSBA.Text, txtXlsFllSBA.Text, txtXlsRefSBA.Text, txtXlsLibSBA.Text, txtXlsLn1SBA.Text, "Lecture de la liste des 7"); },
                    () => { htSbB = GetListe(this, txtFicXlsSBB.Text, txtXlsFllSBB.Text, txtXlsRefSBB.Text, txtXlsLibSBB.Text, txtXlsLn1SBB.Text, "Lecture de la liste des 8"); }
                ); // */
                tssLabel.Text = "Traitement des XML";
                Traite(txtChemRepUd.Text, txtFicXsd.Text, htUd, htCpm, htItem, htSpm, htSol, htEIPC, htSbA, htSbB, txtInfos, tssPbMain.ProgressBar);
                tssLabel.Text = "Traitement terminé";
            }
     
        class UtilsControls {
     
            public delegate void AddControl(Control ctlParent, Control ctlEnfant); // Modèle de fonction (prototype) pour l'instanciation.
            public static void CtlAddControl(Control ctlParent, Control ctlEnfant) {
                try {
                    if (ctlParent.InvokeRequired) { // Gérer les accès concurentiels.
                        ctlParent.Invoke(new UtilsControls.AddControl(UtilsControls.CtlAddControl), ctlParent, ctlEnfant);
                    } else
                        ctlEnfant.Parent = ctlParent;
                } catch (Exception ex) {
                    Log.LogWriter.Instance.WriteException(ex);
                    Log.LogWriter.Instance.FlushLog();
                }
            }
     
            public delegate void setControlDock(Control ctl, DockStyle ds); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlDock(Control ctl, DockStyle ds) {
                if (ctl.InvokeRequired) { // Gérer les accès concurentiels.
                    ctl.Invoke(new UtilsControls.setControlDock(UtilsControls.ctrlDock), ctl, ds);
                } else
                    ctl.Dock = ds;
            }
     
            public delegate void DisposeControlDock(Control ctl); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlDispose(Control ctl) {
                ctl.Dispose();
            }
     
            public delegate void setControlStr(Control ctl, string str); // Modèle de fonction (prototype) pour l'instanciation.
            public static void ctrlAddText(Control ctl, string str) {
                //Application.DoEvents();
                if (ctl.InvokeRequired) { // Gérer les accès concurentiels.
                    ctl.Invoke(new UtilsControls.setControlStr(UtilsControls.ctrlAddText), ctl, str);
                } else
                   ctl.Text += str;
            }
     
            public delegate void setPbInc(ProgressBar ctl, int cmp, int total);
            public static void ProgBarInc(ProgressBar pb, int cmp, int total) { // ToolStripProgressBar
                if (pb.InvokeRequired) {
                    pb.Invoke(new UtilsControls.setPbInc(ProgBarInc), pb, cmp, total);
                } else
                   pb.Value = Math.Min(((int)(((double)cmp / total) * 100)), 100);
            }
            public delegate void setTspbInc(ToolStripProgressBar ctl, int cmp, int total);
            public static void ProgBarInc(ToolStripProgressBar pb, int cmp, int total) { // ToolStripProgressBar
                if (pb.GetCurrentParent().InvokeRequired) {
                    pb.GetCurrentParent().Invoke(new UtilsControls.setPbInc(ProgBarInc), pb, cmp, total);
                } else
                    pb.Value = Math.Min(((int)(((double)cmp / total) * 100)), 100);
            }
     
        }
    Ca, je ne comprends pas du tout.
    David.

  11. #11
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Tu veux dire que tu n'as plus la main sur l'UI ?
    Quand il bloque si tu mets en pause où en est ton dernier traitement ?
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  12. #12
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    Uoi, c'est figé.

    En pause, il est dans le invoke, il sélectionne tout.
    David.

  13. #13
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Tu peux voir les autres threads, notamment celui responsable de ta tâche qui est éventuellement bloqué.
    Sélectionne le en double-cliquant dessus pour voir où il bloque.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  14. #14
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    Je ne comprends pas... Je double clique sur le texte dans VS ?

    En fait, il bloque dans l'interface, mais il fait quand même la dernière des dernières instruction.
    C'est juste la sortie de Invoke qui bloque, j'ai l'impression.
    David.

  15. #15
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Le plus étrange est que les autres tâches ne posent pas de problème et arrivent à s'exécuter...

    Pour moi ton Parallel.Invoke bloque le thread UI => tes pb.Invoke et consort ne devraient pas pouvoir s'exécuter => tout devrait être bloqué!

    Pour voir la liste de tous les threads va dans Debug -> Windows -> Threads
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  16. #16
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    Bon, je désespère.

    Même mon exemple minimaliste bloque. Il s’arrête tantôt à la 4, tantôt à la 7, mais ne va jamais jusqu'au bout.
    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
     
                int nbCoeurs = 2;
                int.TryParse(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"), out nbCoeurs);
                Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = nbCoeurs },  // Task.Factory.StartNew(() => 
                    () => { htSbA = GetListe(this, "Lecture de la liste 1"); },
                    () => { htSbB = GetListe(this, "Lecture de la liste des 2"); },
                    () => { htUd = GetListe(this, "Lecture de la liste 3"); },
                    () => { htEIPCA = GetListe(this, "Lecture de la liste 4"); },
                    () => { htEIPCB = GetListe(this, "Lecture de la liste 5"); },
                    () => { htCpm = GetListe(this, "Lecture de la liste 6"); },
                    () => { htItem = GetListe(this, "Lecture de la liste 7"); },
                    () => { htSpm = GetListe(this, "Lecture de la liste 8"); },
                    () => { htSol = GetListe(this, "Lecture de la liste 9"); }
                ); // */
                tssLabel.Text = "Traitement des XML";
     
            private static Hashtable GetListe(frmMain frm, string texte) {
                Hashtable ret = new Hashtable();
                UtilsControls uc = new UtilsControls(null);
                string msg = "OK. " + texte + ". " + ret.Count + " éléments intégrés." + Environment.NewLine;
                uc.SetText(frm.txtInfos, msg);
                return ret;
            }
     
        class UtilsControls {
            delegate void SetTextCallback(Control ctl, string text);
            public void SetText(Control ctl, string text) {
                if (ctl.InvokeRequired) { // InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread. If these threads are different, it returns true.
                    SetTextCallback d = new SetTextCallback(SetText);
                    ctl.Parent.Invoke(d, new object[] { ctl, text });
                } else {
                    ctl.Text += text;
                }
            }
    }
    Quelqu'un peut m'aider ?

    Merci d'avance.
    David.

  17. #17
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Pour clarifier un peu les choses ajoute un peu de débug à la fin de chaque tâche, e.g. :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    () => { htSbA = GetListe(this, "Lecture de la liste 1"); Debug.WriteLine("========== Liste 1 OK =========="); }
    Pour moi ce message ne devrait jamais s'afficher, le SetText devant bloquer...
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  18. #18
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 063
    Points : 420
    Points
    420
    Par défaut
    Ca m'échappe... en quoi le settext est il bloquant ?
    Il n'est pas juste censé gérer les collisions ?

    Pragmateek, Est ce que c'est possible que tu essayes d'executer mon exemple, il est autonome.
    ca vient peut etre de ma config...
    je suis en 4.0
    David.

  19. #19
    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. Et diable ! Que d'embrouilles... Reprenons dans l'ordre...

    1) Parallel.Invoke est un appel bloquant (il ne retourne que lorsque toutes les actions ont été exécutées). Donc il bloque le thread UI. Et puisque tes opérations sur l'UI doivent se faire sur le thread UI (via Invoke), tu obtiens un deadlock: l'UI attend les ouvriers, les ouvriers attendent l'UI.

    Ce qui est surprenant dans l'histoire c'est qu'une seule des actions invoquées ait pu s'exécuter. Mais ça s'explique très simplement : Parallel.Invoke ne se met pas en attente après avoir mis toutes tes actions dans la file du threadpool. A la place il se met lui-même à exécuter des actions (de façon à favoriser l'exécution locale). Donc certaines actions sont exécutées sur le thread UI. Mais une fois que toutes tes actions ont été dépilées soit par le thread UI (et exécutées) soit par les autres threads (désormais en attente), le thread UI se met en attente des ouvriers.

    La bonne solution est donc de ne pas utiliser Parallel.Invoke (ou alors depuis un autre thread). Je te conseille ceci (note que FromCurrentSynchronizationContext force le code à être exécuté sur le thread UI - le contexte courant au départ, donc pas besoin de Invoke):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Task.WhenAll(<actions à invoquer>).ContinueWith(<code appelé sur le thread UI quand tout est fini>, TaskScheduler.FromCurrentSynchronizationContext())
    Ou, avec await/async :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    await Task.WhenAll(...); // Redonne la main au thread UI
    <code appelé sur le thread UI quand tout est fini>
    "await" est bloquant sans l'être : en fait il place automatiquement la suite de la fonction dans un ContinueWith et retourne imméduatement, libérant ainsi le thread UI. Le code est donc équivalent au précédent. Note que tu devrais marquer ta méthode btnval_click d'un "async" avant le "void".



    2) Pour tes précédents problèmes : un composant créé en arrière-plan peut certes être utilisé en arrière-plan. Mais à partir du moment où tu l'affectes à un parent, alors ce composant doit logiquement appartenir au thread du parent : dans une hiérarchie de contrôles toutes les opérations en cascade (mesure, arrangement, etc) doivent pouvoir être réalisés sur un seul thread. J'imagine donc qu'en changeant le parent de ton contrôle tu l'as rattaché au thread du parent, d'où l'exception après cela (avec la propriété Dock ou la méthode Dispose). Cela dit c'est en partie de la spéculation de ma part car je ne connaissais pas ce comportement lors de l'utilisation de la propriété parent, j'aurais parié sur une exception. Mais puisque ce n'est pas le cas, alors il *faut* que ça change l'affiliation au thread.



    3) Quelques conseils : découple complètement les traitements de l'UI. Crée une simple interface que tu fourniras à ue.GetList à travers laquelle les MAJ de l'UI seront ordonnées. Dans l'idée ta méthode GetListe devrait ressembler à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Hashtable GetListe(string ficXls, string xlsFeuille, string xlsColId, string xlsColLib, string xlsLigne1, string texte, string regexId="") {
                Hashtable ret = new Hashtable();
                if (!string.IsNullOrEmpty(ficXls.Trim()) && (File.Exists(ficXls)) && (int.TryParse(xlsLigne1, out tmp))) {
                    IProgressIndicator pb = StartListGetter(...);
                    ret = ue.GetListe(ficXls, xlsFeuille, xlsColId, xlsColLib, tmp, ref pb, regexId); //tssPbMain
                    EndListGetter(pb);
                } // */
                return ret;
    }
    Ainsi toute la plomberie des Invoke et les opérations UI sont rassemblés dans StartListGetter, TerminateListGetter et IProgressIndicator. Et tu n'auras besoin que d'un seul appel à Invoke pour chaque (tu peux mettre à jour plusieurs contrôles d'un coup).

    Note aussi qu'avec WhenAll tu n'auras pas besoin de tester InvokeRequired: cette propriété sera toujours vraie puisque tu ne seras jamais sur le thread UI.

  20. #20
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Le fait que ton truc marche partiellement est dû au fait que Parallel.Invoke peut exécuter une partie des délégués sur le thread courant.
    Donc ceux qui ont cette chance vont jusqu'au bout, les autres sont bloqués au niveau du ctl.Parent.Invoke comme je le pensais.

    Pour t'asssurer que tous s'exécuteront bien il faut utiliser d'autres threads, et donc on en revient à ma 1ère proposition :
    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
    int nbCoeurs = 2;
                int.TryParse(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"), out nbCoeurs);
                Task.Run(() =>
                    {
                        Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = nbCoeurs },  // Task.Factory.StartNew(() => 
                    () => { htSbA = GetListe(this, "Lecture de la liste 1"); },
                    () => { htSbB = GetListe(this, "Lecture de la liste 2"); },
                    () => { htUd = GetListe(this, "Lecture de la liste 3"); },
                    () => { htEIPCA = GetListe(this, "Lecture de la liste 4"); },
                    () => { htEIPCB = GetListe(this, "Lecture de la liste 5"); },
                    () => { htCpm = GetListe(this, "Lecture de la liste 6"); },
                    () => { htItem = GetListe(this, "Lecture de la liste 7"); },
                    () => { htSpm = GetListe(this, "Lecture de la liste 8"); },
                    () => { htSol = GetListe(this, "Lecture de la liste 9"); }/**/
                ); // */
                        // tssLabel.Text = "Traitement des XML";
                        new UtilsControls().SetText(tssLabel, "Traitement des XML");
                    }
                );
    Ca marche, j'ai testé.

    Expliciter le MaxDegreeOfParallelism n'a aucun intérêt dans ce cas je pense.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Gestion des transactions avec les composants DOA
    Par lper dans le forum Bases de données
    Réponses: 2
    Dernier message: 01/12/2008, 16h06
  2. problème avec les composant graphique de gwt-ext
    Par ensienne2008 dans le forum GWT et Vaadin
    Réponses: 9
    Dernier message: 16/09/2008, 09h32
  3. Problème avec les pilotes graphique ATI
    Par vdumont dans le forum Matériel
    Réponses: 5
    Dernier message: 06/04/2006, 09h05
  4. Violation d'accès avec les composants Word 97/ 2000
    Par edechaux dans le forum Composants VCL
    Réponses: 3
    Dernier message: 07/03/2006, 09h48
  5. Réponses: 13
    Dernier message: 19/01/2006, 10h06

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