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 :

Problème avec le multi-threading


Sujet :

C#

  1. #1
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut Problème avec le multi-threading
    Bonjour à tous,

    j'ai eu quelques problèmes récemment avec le multi-threading et j'ai réussi jusqu'à présent en utilisant d'autres types, en faisant un peu de bricolage. Mais là je suis face à une erreur que je ne comprends pas.

    Dans la boucle ci-dessous qui s'exécute parallèlement grâce à Parallel.ForEach, qui énumère tous les éléments de la liste list qui contient des Model3D, je crée deux objets qui sont des parties spéciales de currentChildModel3D, la variable locale du foreach en gros.
    Et j'ai l'erreur comme quoi le thread n'a pas accès à l'objet car il n'en ai pas propriétaire, alors que je viens de le créer en local dans la boucle ! Pourtant il me semble bien que mon instanciation d'objet ne correspond pas à une référence mais bien à un type valeur... Je vous laisse juger:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Parallel.ForEach(listChildModel3D, currentChildModel3D =>
                    {
                        GeometryModel3D gm1 = new GeometryModel3D();
                        gm1 = (GeometryModel3D)currentChildModel3D;
    
                        MeshGeometry3D mesh1 = new MeshGeometry3D(); 
                        mesh1 = gm1.Geometry as MeshGeometry3D;//Le thread appelant ne peut pas accéder à l'objet car il n'en ai pas propriétaire
                        
    Geometry g2 = Create2DGeometryFromModel3D(currentChildModel3D, matrixList[listChildModel3D.IndexOf(currentChildModel3D)],gm1,mesh1 );
                        g1.Children.Add(g2); //Ajout à la variable globale, un GeometryGroup
    
                    });
    Je ne vois vraiment pas d'où provient l'erreur étant donné que la variable mesh1 est locale !

    Si quelqu'un avait une idée ce serait super !

    Merci d'avance

  2. #2
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par mikeycast Voir le message
    Bonjour à tous,

    j'ai eu quelques problèmes récemment avec le multi-threading et j'ai réussi jusqu'à présent en utilisant d'autres types, en faisant un peu de bricolage. Mais là je suis face à une erreur que je ne comprends pas.

    Dans la boucle ci-dessous qui s'exécute parallèlement grâce à Parallel.ForEach, qui énumère tous les éléments de la liste list qui contient des Model3D, je crée deux objets qui sont des parties spéciales de currentChildModel3D, la variable locale du foreach en gros.
    Et j'ai l'erreur comme quoi le thread n'a pas accès à l'objet car il n'en ai pas propriétaire, alors que je viens de le créer en local dans la boucle ! Pourtant il me semble bien que mon instanciation d'objet ne correspond pas à une référence mais bien à un type valeur... Je vous laisse juger:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Parallel.ForEach(listChildModel3D, currentChildModel3D =>
                    {
                        GeometryModel3D gm1 = new GeometryModel3D();
                        gm1 = (GeometryModel3D)currentChildModel3D;
    
                        MeshGeometry3D mesh1 = new MeshGeometry3D(); 
                        mesh1 = gm1.Geometry as MeshGeometry3D;//Le thread appelant ne peut pas accéder à l'objet car il n'en ai pas propriétaire
                        
    Geometry g2 = Create2DGeometryFromModel3D(currentChildModel3D, matrixList[listChildModel3D.IndexOf(currentChildModel3D)],gm1,mesh1 );
                        g1.Children.Add(g2); //Ajout à la variable globale, un GeometryGroup
    
                    });
    Je ne vois vraiment pas d'où provient l'erreur étant donné que la variable mesh1 est locale !

    Si quelqu'un avait une idée ce serait super !

    Merci d'avance
    A mon humble avis c'est plutôt gm1 qui pose problème!
    D'ailleurs tu créés un GeometryModel3D pour rien...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    GeometryModel3D gm1 = new GeometryModel3D();
    gm1 = (GeometryModel3D)currentChildModel3D;
    se remplace par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GeometryModel3D gm1 = (GeometryModel3D)currentChildModel3D;
    Edit: Euh mais je viens de remarquer que tu fais tout à l'envers en fait
    C'est pareil pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MeshGeometry3D mesh1 = new MeshGeometry3D(); 
    mesh1 = gm1.Geometry as MeshGeometry3D;
    A quoi ca te sert de créer un MeshGeometry3D si c'est pour l'écraser tout de suite après?

  3. #3
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Bon j'ai feuilleté MSDN un peu plus et j'ai quelques mauvaises nouvelles.
    Tout ce que tu manipules sont des instances de classes (et sont donc par conséquence des types références). De plus GeometryModel3D est un DispatcherObject ce qui signifie que seul le thread qui l'a créée peut y accéder (via la propriété Dispatcher de cet objet). Par conséquent, si il est créée sur le thread de l'UI tu ne peux pas le manipuler dans un autre et si tu le créée dans un autre tu ne peux pas le manipuler avec le thread de l'UI.

    Note: c'était couru d'avance que c'était des types références, car le cast ne sert à rien sur des types valeurs étant donné qu'il n'y a pas d'héritage dans les types valeurs.

  4. #4
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Salut,

    Merci beaucoup pour ta réponse. En fait si je m'étais un peu compliqué la vie en écrivant le code en deux lignes au lieu d'une c'est parce que je voulais forcer la création d'une nouvelle instance (avec le new). Mais comme tu le dis c'est dommage c'est forcément une référence...

    Est-ce que tu aurais une idée qui permettrait de passer outre cette difficulté? J'ai bien pensé au mot lock mais évidemment ca ne fonctionne quand même pas étant donné que c'est un DispatcherObject...

    Est-ce que tu saurais manipuler ce type d'objets 3D pour pouvoir l'extraire dans des types valeurs ou thread-safe (tableaux?) afin que je puisse créer autant de gm1 et de mesh qu'il y a de threads? (variables locales)

  5. #5
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par mikeycast Voir le message
    Salut,

    Merci beaucoup pour ta réponse. En fait si je m'étais un peu compliqué la vie en écrivant le code en deux lignes au lieu d'une c'est parce que je voulais forcer la création d'une nouvelle instance (avec le new). Mais comme tu le dis c'est dommage c'est forcément une référence...

    Est-ce que tu aurais une idée qui permettrait de passer outre cette difficulté? J'ai bien pensé au mot lock mais évidemment ca ne fonctionne quand même pas étant donné que c'est un DispatcherObject...

    Est-ce que tu saurais manipuler ce type d'objets 3D pour pouvoir l'extraire dans des types valeurs ou thread-safe (tableaux?) afin que je puisse créer autant de gm1 et de mesh qu'il y a de threads? (variables locales)
    Non c'est impossible, ce type d'objet doit uniquement être manipulé sur le thread de l'UI. Que cherches tu as faire ?

  6. #6
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    En fait la fonction a pour but de calculer le contour d'objets 3D. A partir de l'objet 3D on calcule sa projection et on en prend le contour.

    Je n'ai pas écrit ce code, je ne peux malheureusement pas expliquer pourquoi telle ou telle solution a été choisie mais juste ce que j'en ai compris.

    Le modèle 3D complet contient tous les objets, mais les calculs se font séparément. (Dans mon bout de code chaque currentChildModel3D est un objet). J'avais au début choisi de paralléliser le calcul des contours, mais j'ai trouvé cela plus judicieux de paralléliser le calcul de chaque objet. C'est-à-dire qu'un thread calcule le contour d'un objet, et pas une partie du contour d'un objet pour tous les objets.

    Seulement voilà, le modèle 3D même enfant ne semble pas pouvoir être utilisé séparément par plusieurs threads.

    En gros c'est toujours la même fonction "Create2DGeometryFromModel3D" qui est appelée, et qui fait le tri entre un modèle ou une famille de modèles (lorsque c'est une famille, elle s'appelle de manière récursive pour chaque modèle, c'est la partie que je souhaite paralléliser).

    J'espère avoir été assez clair dans mes explications, je pourrais te donner plus de détails mais je ne sais pas si c'est utile.

    Merci beaucoup !

  7. #7
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par mikeycast Voir le message
    En fait la fonction a pour but de calculer le contour d'objets 3D. A partir de l'objet 3D on calcule sa projection et on en prend le contour.

    Je n'ai pas écrit ce code, je ne peux malheureusement pas expliquer pourquoi telle ou telle solution a été choisie mais juste ce que j'en ai compris.

    Le modèle 3D complet contient tous les objets, mais les calculs se font séparément. (Dans mon bout de code chaque currentChildModel3D est un objet). J'avais au début choisi de paralléliser le calcul des contours, mais j'ai trouvé cela plus judicieux de paralléliser le calcul de chaque objet. C'est-à-dire qu'un thread calcule le contour d'un objet, et pas une partie du contour d'un objet pour tous les objets.

    Seulement voilà, le modèle 3D même enfant ne semble pas pouvoir être utilisé séparément par plusieurs threads.

    En gros c'est toujours la même fonction "Create2DGeometryFromModel3D" qui est appelée, et qui fait le tri entre un modèle ou une famille de modèles (lorsque c'est une famille, elle s'appelle de manière récursive pour chaque modèle, c'est la partie que je souhaite paralléliser).

    J'espère avoir été assez clair dans mes explications, je pourrais te donner plus de détails mais je ne sais pas si c'est utile.

    Merci beaucoup !
    Ben ce qu'il faudrait c'est récupérer les infos qui t'intéressent et faire les calculs avec (sans utiliser ces objets). Il doit y avoir des librairies qui font ce genre de calcul en .Net

  8. #8
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Est-ce que tu aurais une idée qui permettrait de passer outre cette difficulté? J'ai bien pensé au mot lock mais évidemment ca ne fonctionne quand même pas étant donné que c'est un DispatcherObject...
    Dans la classe MyControl qui a créé l'objet, on peut créer une fonction MyMethod(Arg1,Arg2) qui manipule l'objet et l'appeler depuis un autre thread avec un invoke.

    Exemple pour une methode retournant un int :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int MyMethodResult ;
    MyControl.Invoke(new MethodInvoker(delegate() { MyMethodResult= MyControl.MyMethod(Arg1,Arg2);} )) ;
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  9. #9
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par Graffito Voir le message
    Dans la classe MyControl qui a créé l'objet, on peut créer une fonction MyMethod(Arg1,Arg2) qui manipule l'objet et l'appeler depuis un autre thread avec un invoke.

    Exemple pour une methode retournant un int :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int MyMethodResult ;
    MyControl.Invoke(new MethodInvoker(delegate() { MyMethodResult= MyControl.MyMethod(Arg1,Arg2);} )) ;
    Pour le coup, ca c'est valable pour du Winform, ici c'est du WPF
    Et le résultat c'est que tout sera exécuté sur le même thread, par conséquent ca va créer un goulot d'étranglement.

  10. #10
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Pour le coup, ca c'est valable pour du Winform, ici c'est du WPF
    C'est effectivement une solution que j'utilise en WinForms (je n'ai jamais rien developpé en WPF ) .
    Pour ma culture personelle, pourquoi la même solution ne fonctionnerait-elle pas de façon analogue en WPF?
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  11. #11
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par Graffito Voir le message
    C'est effectivement une solution que j'utilise en WinForms (je n'ai jamais rien developpé en WPF ) .
    Pour ma culture personelle, pourquoi la même solution ne fonctionnerait-elle pas de façon analogue en WPF?
    Bon c'est du détail hein mais c'est juste que la méthode Invoke n'existe pas directement sur les contrôles WPF.
    Il faut passer par le Dispatcher. Les contrôles ont une propriété Dispatcher et c'est ce dispatcher qui dispose de la méthode Invoke.

  12. #12
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Ainsi en WPF, le code serait ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int MyMethodResult ;
    MyControl.Dispatcher.Invoke(new Action(delegate()  { MyMethodResult= MyControl.MyMethod(Arg1,Arg2);} )) ;
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  13. #13
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Et pour mon cas une fonction qui ne fait juste qu'instancier ca marcherait aussi? Il suffirait que j'instancie l'objet dans le thread qui va l'utiliser en fait c'est bien ca?

  14. #14
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Bien qu'nstancier des Forms dans un tread secondaire soit possible (au moins en winforms) quoique pas très évident, instancier un control que l'on transférerait dans une form créée dans un autre thread est probablement impossible.
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  15. #15
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bon et bien je ne pense pas que j'arriverai à m'en sortir avec cela alors. Je vais donc réenvisager ma première méthode : paralléliser le dessin du contour pour chaque objet.

    Cela consistait au début à relier les points composant un objet 3 par 3 puis à les ranger dans une Geometry à l'aide de la méthode Geometry.Combine(..,..,GeometryCombineMode.Union). Il est cependant précisé sur MSDN que cette fonction est fortement déconseillée pour les unions car "peut nécessiter beaucoup d'UC". J'ai donc essayé de procéder comme ils le suggèrent, à l'aide de GeometryGroup. La performance est vraiment excellente (division du temps de calculs par 10 !), seulement voilà.. je n'obtient pas un contour : Nom : Contour mal tracé 1.jpg
Affichages : 145
Taille : 3,5 Ko

    En fait j'ai cru comprendre que l'avantage du Combine(Union) était que ca supprimait les intersections ! Pour rappel, les opérations élémentaires : Nom : geometry.jpg
Affichages : 256
Taille : 67,6 Ko

    Auriez-vous une idée pour effectuer une opération similaire sans passer par un "combine"?

    Merci

  16. #16
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Bonjour,

    Comme on n'est plus dans la problématique liée au multi-threading, je te conseille donc d'ouvrir une nouvellle discussion sur l'aspect "Geometry".
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  17. #17
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11

  18. #18
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Bonjour à mikeycast....& à tous.....

    Le Dispatcher WPF est une espece de scheduler qui met en queue les objets en attente d'affichage sur l'UI...(il dispose meme d'une prop Priority)....
    Les appels sont donc uniquement Asynchrones(genre BeginInvoke en WinForm)....
    Neansmoins la remarque de Graffitto tombe à bon escient et comme le souhaite mikeycast on peut obtenir une instance d'un objet reference reference dans l'ui via le Dispatcher UI moyennat un delegate :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // nota-bene :this se refere à un form ou un control 
    ModelMesh currentChildModel3D =
                           (ModelMesh)this.Dispatcher.Invoke(
                           (Func<ModelMesh>)(() =>
                                   this.listChildModel3D.ElementAt(j)));
    Le seul hic dans les calculs de mickeycast c'est la suite :
    -un ModelVisual3D possede un membre MeshGeometry type reference
    -le MesGeomtry possede un membre Collection Positions type reference(sommets-points du mesh)
    pour lesquels il faut passer aussi par le Dispatcher suivant le code decrit ci-dessus............

    Pour la TPL je lui suggere plutot Task.Factor qui execute egalement des boucles for paralleles mais qui gerent mieux l'interaction avec l'UI avec son WaitForALL ou WaitForOne..........

    voici le code complet qui l'illustre tout cela avec 3 ListBox :
    - 1er affiche noms des model et sommets ( Positions) du MeshGeomtry original....
    - 2eme affiche noms des models et sommets du MeshGeometry apres un calcul parallelise...
    - 3eme stocke uniquement les Mesh modifies (le "g1") sans reference au modele.
    - le mesh pris en exemple comporte trois sommets seulement
    - la fonction Create2DGeometryFromModel3D : 1000 Iterations
    sur chaque Positions[I] avec sommation Point.X,Point.Y,Point.Z..,extraction de racine carree de Point.X,Point.Y,Point.Z ce qui done un nouveau Positions[I] qu'on store dans le MeshGeometry.....
    code .cs du du ModelMesh exemple :
    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
    117
    118
    119
    120
    121
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.ObjectModel;
    using System.Windows.Media.Media3D;
    using System.ComponentModel;
    namespace WpfParallellTask
    {
     
        public class ModelMesh : INotifyPropertyChanged
        {
            public ModelMesh()
            {
                this.Name = "";
                this.Geom=new GeometryModel3D();
                this.Mesh = new MeshGeometry3D();
            }
            private string m_Name;
            public string Name
            {
                get { return m_Name; }
                set
                {
                    m_Name = value;
                    OnPropertyChanged("Name");
                }
            }
            private GeometryModel3D m_Geom;
            public GeometryModel3D Geom 
            {
                get { return m_Geom; }
                set
                {
                    m_Geom = value;
                    OnPropertyChanged("Geom");
                }
            }
            private MeshGeometry3D m_Mesh;
            public MeshGeometry3D Mesh
            {
                get { return m_Mesh; }
                set 
                { 
                    m_Mesh=value;
     
                    if (m_Mesh != null)
                    {
                        this.Positions = m_Mesh.Positions;
                        this.Geom.Geometry = m_Mesh;
                        OnPropertyChanged("Mesh");
                    }
              } 
            }
            private Point3DCollection m_Positions;
            public Point3DCollection Positions
            {
                get { return m_Positions; }
                set
                {
                    m_Positions = value;
                    if (m_Positions != null)
                    {
                        this.Geom.Geometry =Mesh;
                        OnPropertyChanged("Positions");
                    } 
                }
            }
     
            #region INotifyPropertyChanged Membres
     
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string propName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propName));
     
                }
     
            }
            #endregion
        }
        public class ModelMeshes : ObservableCollection<ModelMesh>
        {
     
            GeometryModel3D geom;
            MeshGeometry3D mesh;
            ModelMesh mm;
            Random rnd = new Random();
     
                public ModelMeshes()
                {
     
                    for (int i = 0; i < 9; i++)
                    {
     
                        mesh = new MeshGeometry3D();
     
                        for (int j = 0; j < 3; j++)
                        {
                            mesh.Positions.Add(new Point3D(100*rnd.NextDouble(), 100*rnd.NextDouble(),100*rnd.NextDouble()));
     
                        }
                        geom = new GeometryModel3D();
                        geom.Geometry  = mesh;
     
                        mm = new ModelMesh();
                        mm.Name = "MeshModel" + i.ToString();
                        mm.Geom = geom ;
                        mm.Mesh = mesh;
                        this.Add(mm);
     
                    }
     
                }
     
            }
     
        }
    code xaml du winform:
    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
     
    <Window x:Class="WpfParallellTask.WindowTaskListObjects"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfParallellTask"
            Title="WindowTaskListObjects" Height="350" Width="525">
        <Window.Resources>
     
            <DataTemplate 
                x:Key="TemplateModel"
                DataType="{x:Type local:ModelMesh}">
                <StackPanel Orientation="Horizontal" >
                    <TextBlock  Padding="10" Text="{Binding Path=Name}"/>
                    <TextBlock  Padding="10" Text="{Binding Path=Positions,StringFormat=N:{0:F2}}"/>
     
                </StackPanel>
            </DataTemplate>
            <DataTemplate 
                x:Key="TemplateMeshes"
                DataType="{x:Type local:ModelMesh}">
                <StackPanel Orientation="Horizontal" >
                    <TextBlock  Padding="10" Text="{Binding Path=Positions,StringFormat=N:{0:F2}}"/>
                </StackPanel>
            </DataTemplate>
     
        </Window.Resources>
        <StackPanel Orientation="Vertical" >
            <DockPanel>
                <Button 
                    DockPanel.Dock="Left" 
                    Name="start"
                    Height="40"
                    Content="StartTask"
                    Click="start_Click">
                </Button>
                <TextBlock
                    DockPanel.Dock="Left" 
                    Name="textBlock1"
                    Height="40"
                    FontSize="14"
                    Padding="10"
                    Foreground="Brown">
     
                </TextBlock>
                <Label
                    DockPanel.Dock="Bottom" 
                    Name="label1"
                    Padding="10"
                    Height="40"
                    FontSize="14"
                    Foreground="Red" >
     
                </Label>
            </DockPanel>
            <StackPanel Orientation="Vertical">
                <ListBox
                    DockPanel.Dock="Left"
                    Name="lbModelOrginal"
                    Height="150"
                    ScrollViewer.VerticalScrollBarVisibility="Auto"
                    ScrollViewer.HorizontalScrollBarVisibility="Auto"
                    ItemTemplate="{StaticResource TemplateModel}"
                    ItemsSource="{Binding}">
     
                </ListBox>
                <ListBox
                    DockPanel.Dock="Left"
                    Name="lbModel"
                    Height="150"
                    ScrollViewer.VerticalScrollBarVisibility="Auto"
                    ScrollViewer.HorizontalScrollBarVisibility="Auto"
                    ItemTemplate="{StaticResource TemplateModel}"
                    ItemsSource="{Binding}">
     
                </ListBox>
                <ListBox
                    DockPanel.Dock="Right"
                    Name="lbMeshes"
                    Height="150"
                    ScrollViewer.VerticalScrollBarVisibility="Auto"
                    ScrollViewer.HorizontalScrollBarVisibility="Auto"
                    ItemTemplate="{StaticResource TemplateMeshes}"
                    ItemsSource="{Binding}">
                </ListBox >
     
            </StackPanel>
        </StackPanel>
    </Window>
    code behind .cs :
    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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Diagnostics;
    using System.Threading.Tasks;
    using System.Windows.Media.Media3D;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    namespace WpfParallellTask
    {
        /// <summary>
        /// Logique d'interaction pour WindowTaskListObjects.xaml
        /// </summary>
        public partial class WindowTaskListObjects : Window
        {
            ModelMeshes originallistChildModel3D = null; 
            ModelMeshes listChildModel3D = null;
            ObservableCollection<MeshGeometry3D> G = new ObservableCollection<MeshGeometry3D>();
     
            public WindowTaskListObjects()
            {
                InitializeComponent();
     
                originallistChildModel3D = new ModelMeshes();
                listChildModel3D = new ModelMeshes();
                this.lbModelOrginal.ItemsSource = originallistChildModel3D;
                this.lbModel.ItemsSource = listChildModel3D;
                this.lbMeshes.ItemsSource =G;
     
            }
     
     
            private void start_Click(object sender, RoutedEventArgs e)
            {
                textBlock1.Text = "";
                label1.Content = "Milliseconds: ";
                G.Clear();
                var watch = Stopwatch.StartNew();
                List<Task> tasks = new List<Task>();
                for (int i = 0; i < listChildModel3D.Count; i++)
                {
                    //Closure :changement d'indice important 
                    int j = i;
                    var t = Task.Factory.StartNew(() =>
                        {
                           // 4 Invoke Dispatcher UI: pour obtenir une Instance d'un objet UI....
                           ModelMesh currentChildModel3D =
                           (ModelMesh)this.Dispatcher.Invoke(
                           (Func<ModelMesh>)(() =>
                                    listChildModel3D.ElementAt(j)));
     
                            GeometryModel3D geom =
                           (GeometryModel3D)Dispatcher.Invoke(
                           (Func<GeometryModel3D>)(() =>
                                    listChildModel3D.ElementAt(j).Geom));
     
                            MeshGeometry3D mesh = (MeshGeometry3D)Dispatcher.Invoke(
                            (Func<MeshGeometry3D>)(() =>
                             {
                                 MeshGeometry3D m=
                                     (MeshGeometry3D)listChildModel3D.ElementAt(j).Geom.Geometry;
                                 return m;}
                             ));
     
                           Point3DCollection positions = (Point3DCollection)Dispatcher.Invoke(
                           (Func<Point3DCollection>)(() =>
                           {
                               Point3DCollection pts =
                                   (Point3DCollection )((MeshGeometry3D)listChildModel3D.ElementAt(j).Geom.Geometry).Positions;
                               return pts;
                           }
                             ));
     
                           var resultGeomModel = (MeshGeometry3D)Dispatcher.Invoke(
                                (Func<MeshGeometry3D>)(() => 
                                {
                                    return Create2DGeometryFromModel3D(j,currentChildModel3D, geom, mesh, positions);
                                }
                                ));
     
     
     
                            //Invoke Dispatcher UI to display Message(genre winform pour afficher des data....
                            this.Dispatcher.BeginInvoke(new Action(() =>
     
                                 textBlock1.Text = "root " + j.ToString() + " " +
                                                     resultGeomModel.Positions.Count .ToString()  +
                                                     Environment.NewLine)
                            , null
                            );
                            //Invoke Dispatcher UI (genre winform pour lui demander de mettre un objet à lui :G)
                            this.Dispatcher.BeginInvoke(new Action(() =>
     
                              G.Add(resultGeomModel))
                           , null); 
                        }
                    );
     
     
     
                    tasks.Add(t);
                }
     
                //Invoke Dispatcher UI when all tasks are terminated
                Task.Factory.ContinueWhenAll(tasks.ToArray(),
                      result =>
                      {
                          var time = watch.ElapsedMilliseconds;
                          this.Dispatcher.BeginInvoke(new Action(() =>
                              label1.Content += time.ToString()));
     
                      }
                    );
     
     
                this.lbModel.ItemsSource = listChildModel3D;
                this.lbMeshes.ItemsSource = G;
     
            }
            public MeshGeometry3D Create2DGeometryFromModel3D(int index,ModelMesh model, GeometryModel3D geom, MeshGeometry3D mesh, Point3DCollection positions)
            {
                double sumX =0.0;
                double sumY =0.0;
                double sumZ =0.0;
     
                int niter = 10000;
                for (int i = 0; i < positions.Count; i++)
                {
     
                    for (int k = 1; k < niter; k++)
                    {
                        sumX +=  positions[i].X;
                        sumY +=  positions[i].Y;
                        sumZ +=  positions[i].Z;
                    }
     
                    mesh.Positions[i] = new Point3D( Math.Sqrt(sumX), Math.Sqrt(sumY), Math.Sqrt(sumZ));
                    model.Mesh = mesh;  
                    listChildModel3D[index] = model;
                }
     
     
                return mesh;
            }
     
     
     
     
        }
    }
    Pour la recursivite il faut voir MSDN Doc pour voir les conditions à laquelle doivent satisfaire le calcul recursif ainsi que les donnees.............

    J'ai vu egalement ton post sur le calcul du contour d'un objet 3D ...
    Le contour ne peut etre que 2D donc relatif aux coords du Viewport3D(ou coors d'ecran) cela va sans dire..................
    Dans le principe tu dois d'abord trouver
    -le BoundRect2D du ModelVisual3D.,ce qui est assez simple grace à MyVisual3d.TransformToancestor(MyViewPort).GetBoundRect()...
    -le plus embetant c'est les Positions pour lequelles il faut utiliser Toolkit 3D de codeplex..pour obtenir un point2D relatif à MyViewPort..
    Apres c'est facile on recupere les Positions dont les X sont egales a BoundRect.Left ou BoundRect.Rigth & les Y egales à BoundRect.Top ou BoundRect.Bottom.....
    Je te posterai le code exemple des que j'aurais un moment de libre..........

    bon code........-

  19. #19
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Quel est l'interêt de paralléliser si derrière il n'y a qu'un thread qui peut traiter la chose?

  20. #20
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bonjour à tous,

    Merci beaucoup pour ta réponse Mabrouki ! Je viens de passer un bon moment à implémenter cela, et je comptais appeler la fonction Create2DGeometryFromModel3D sans passer par le Dispatcher, sinon effectivement ca ne sert à rien de paralléliser si toutes les fonctions sont exécutées avec le Dispatcher...

    Voici donc mon code, qui tient en une seule feuille car je ne me suis pas servi de ta classe ModelMesh :
    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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    public static Geometry Create2DGeometryFromModel3D(Model3D model3D, Matrix3D transform2D, GeometryModel3D geom=null, MeshGeometry3D mesh=null, Point3D[] points=null, Int32[] indicies=null)
            {
                if (model3D is GeometryModel3D)
                {
                    if (mesh != null)
                    {
                        Matrix3D screenTransform = multiplyMatrix3D(geom.Transform, transform2D);
                        screenTransform.Transform(points);
     
                        if (mesh.TriangleIndices == null || mesh.TriangleIndices.Count == 0)
                        {
                            // Combined all triangle into one geometry (union)
                            Geometry g1 = new StreamGeometry();
                            for (int i = 0; i < points.Length; i += 3)
                            {
                                var g2 = new StreamGeometry();
                                using (StreamGeometryContext ctx = g2.Open())
                                {
                                    ctx.BeginFigure(new Point(points[i].X, points[i].Y), true, true);
                                    ctx.LineTo(new Point(points[i + 1].X, points[i + 1].Y), true, false);
                                    ctx.LineTo(new Point(points[i + 2].X, points[i + 2].Y), true, false);
                                }
                                g2.Freeze();
     
                                g1 = Geometry.Combine(g1, g2, GeometryCombineMode.Union, null);
                            }
                            g1.Freeze();
                            return g1;
                        }
                        else
                        {
                            // Combined all triangle into one geometry (union)
                            Geometry g1 = new StreamGeometry();
                            for (int i = 0; i < indicies.Length; i += 3)
                            {
                                var g2 = new StreamGeometry();
                                using (StreamGeometryContext ctx = g2.Open())
                                {
                                    ctx.BeginFigure(new Point(points[indicies[i]].X, points[indicies[i]].Y), true, true);
                                    ctx.LineTo(new Point(points[indicies[i + 1]].X, points[indicies[i + 1]].Y), true, false);
                                    ctx.LineTo(new Point(points[indicies[i + 2]].X, points[indicies[i + 2]].Y), true, false);
                                }
                                g2.Freeze();
     
                                g1 = Geometry.Combine(g1, g2, GeometryCombineMode.Union, null);
                            }
                            g1.Freeze();
                            return g1;
                        }
                    }
                }
                else if (model3D is Model3DGroup)
                {
                    ObservableCollection<Model3D> listChildModel3D = new ObservableCollection<Model3D>();
                    var group = (Model3DGroup)model3D;
                    GeometryGroup g1 = new GeometryGroup();
     
                    foreach (Model3D childModel3D in group.Children)
                    {
                        listChildModel3D.Add(childModel3D);
                    }
                    List<Task> tasks = new List<Task>();
                    for (int i = 0; i < listChildModel3D.Count; i++)
                    {
                        //Closure :changement d'indice important 
                        int j = i;
                        var t = Task.Factory.StartNew(() =>
                        {
                            // 4 Invoke Dispatcher UI: pour obtenir une Instance d'un objet UI....
     
                            GeometryModel3D geom1 =
                           (GeometryModel3D)Application.Current.Dispatcher.Invoke(
                           (Func<GeometryModel3D>)(() =>
                               {
                                   return (GeometryModel3D)listChildModel3D[j];
                               }));
     
     
                            MeshGeometry3D mesh1 = (MeshGeometry3D)Application.Current.Dispatcher.Invoke(
                            (Func<MeshGeometry3D>)(() =>
                            {
                                return geom1.Geometry as MeshGeometry3D;
                            }));
     
     
                            if (mesh1!=null)
                            {
     
                                Point3D[] points1 = (Point3D[])Application.Current.Dispatcher.Invoke(
                                (Func<Point3D[]>)(() =>
                                {
     
                                        Point3D[] positions = new Point3D[mesh1.Positions.Count];
                                        mesh1.Positions.CopyTo(positions, 0);
                                        return positions;
     
                                }));
     
                                Geometry g2 = Create2DGeometryFromModel3D(listChildModel3D[j], multiplyMatrix3D(model3D.Transform, transform2D), geom1, mesh1, points1, null);
                                g1.Children.Add(g2);
     
                            }
                            else
                            {
                                Int32[] indicies1 = (Int32[])Application.Current.Dispatcher.Invoke(
                                (Func<Int32[]>)(() =>
                                {
                                    Int32[] table = new Int32[mesh.TriangleIndices.Count];
                                    mesh.TriangleIndices.CopyTo(table, 0);
                                    return table;
                                }));
     
                                Geometry g2 = Create2DGeometryFromModel3D(listChildModel3D[j], multiplyMatrix3D(model3D.Transform, transform2D), geom1, mesh1, null, indicies1);
                                g1.Children.Add(g2);
                            }
     
     
                            });
     
                        tasks.Add(t);
                    }
     
                    //Invoke Dispatcher UI when all tasks are terminated
                    Task.Factory.ContinueWhenAll(tasks.ToArray(),
                          result =>
                          {
                              g1.Freeze();
                              return (Geometry)g1;
                          }
                        );
                }
                return new StreamGeometry();
             }
    Pour la structure globale : Si le Model3D en entrée est une famille d'objet, alors on passe dans la partie d'en bas, où j'ai utilisé ce que tu m'as dit. Si c'est un objet, alors on est dans l'une des deux boucles en haut.
    Lorsque c'est une famille, on crée les objets nécessaires avec le dispatcher puis on appelle la fonction de façon récursive pour traiter les objets un à un dans chaque thread.

    Malheureusement ca ne fonctionne pas, je n'ai pas la permission d'exécuter cette fonction dans ce thread...comme avant finalement...

Discussions similaires

  1. Problème avec les multi-threads
    Par Dominique49 dans le forum Général Java
    Réponses: 5
    Dernier message: 12/12/2011, 16h20
  2. [SFML] Problème avec affichage en thread
    Par black is beautiful dans le forum SFML
    Réponses: 0
    Dernier message: 05/05/2009, 11h33
  3. Problème avec repaint() et Thread.sleep
    Par fab13 dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 13/08/2008, 00h02
  4. Problème avec TList et Threads
    Par necralbert dans le forum Composants VCL
    Réponses: 6
    Dernier message: 23/08/2007, 15h12
  5. Problème avec la multi-sélection dans une zone de liste
    Par Mimisio dans le forum VBA Access
    Réponses: 2
    Dernier message: 16/07/2007, 17h23

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