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++Builder Discussion :

TThread et multiprocesseur


Sujet :

C++Builder

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut TThread et multiprocesseur
    Salut à tous,

    A chaque jour son petit sujet...

    Je travail sur la création de thread afin de faire du "parallèle". Voici le petit thread de chronométrage que j'ai "créé" :

    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
    #ifndef chronometreH
    #define chronometreH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    //---------------------------------------------------------------------------
    class ThChrono : public TThread
    {
    private:
    protected:
            void __fastcall Execute();
            void __fastcall AffMessage();
     
    public:
            __fastcall ThChrono(bool CreateSuspended);
     
            LARGE_INTEGER  start;      //!< The start time of the chronometer
            LARGE_INTEGER  tic;
            LARGE_INTEGER  FQPF;
     
            bool           HRPCAvail;  //!< Is there an available HRPC
     
            AnsiString millit;
            double result;
    };
    //---------------------------------------------------------------------------
    #endif
    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
    #include <vcl.h>
    #pragma hdrstop
     
    #include "chronometre.h"
    #include "page_essai.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
     
    __fastcall ThChrono::ThChrono(bool CreateSuspended)
            : TThread(CreateSuspended)
    {
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::Execute()
    {
     
            HRPCAvail=QueryPerformanceCounter(&start); //memo du temps de start
            if (!HRPCAvail)   //si le compteur n'était pas disponible
            {
              start.LowPart = ::GetTickCount();   //basse resolution
              start.HighPart = 0;
            }
     
            while (!Terminated)
            {
               if (HRPCAvail) //si le compteur haute resolution était dispo
               {
                 QueryPerformanceCounter(&tic); //recup du temps
     
                 QueryPerformanceFrequency(&FQPF); //recup de la frequence
     
                 //resultat en msec
                 result=static_cast<double>(tic.QuadPart - start.QuadPart) * 1000
                  /static_cast<double>(FQPF.QuadPart);
               }
               else //si le compteur n'était pas disponible
               {
                 tic.LowPart = ::GetTickCount();
                 tic.HighPart = 0;
     
                 result = 0;
                 //resultat
                 result=tic.LowPart - start.LowPart;
     
               }
               millit = AnsiString(result);
               Synchronize(AffMessage);
            }
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::AffMessage()
    {
           ecran_essai->Label1->Caption = millit;
    }
    Je met créé entre guillemet car j'ai énormément pompé sur le code trouvé dans ce poste

    Ma question est de savoir s'il existe un moyen de s'assurer ou de forcer l'utilisation des différents cœurs du PC? Un coeur pour le process principal et un autre pour les threads.

    Même si mon process n'est composé que de tâches durant plusieurs centième de seconde, que ce chrono est "riche" pour mon utilisation, je préfère assuré le process.

  2. #2
    Membre très actif Avatar de nirgal76
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2007
    Messages
    923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 923
    Par défaut
    Tu as la fonction SetThreadAffinityMask qui permet de définir les coeurs que pourras utiliser ton thread

    http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

    DWORD_PTR WINAPI SetThreadAffinityMask(
    __in HANDLE hThread,
    __in DWORD_PTR dwThreadAffinityMask
    );

    hThread : premier paramètre, l'ID de ton thread
    dwThreadAffinityMask : le masque d'utilisation des cores. 1 bit par coeur. bit de poids faible pour le core n°1.
    exemple :
    pour n'utiliser que le core n°1, tu mets 0x1
    pour n'utiliser que le core n°2, tu mets 0x2
    pour n'utiliser que les core n°1 et 2, tu mets 0x3
    pour n'utiliser que le core n°3, tu mets 0x4
    pour n'utiliser que les core n°1 et 3, tu mets 0x5
    pour n'utiliser que les core n°2 et 3, tu mets 0x6
    pour n'utiliser que les core n°1, 2 et 3, tu mets 0x7
    ...
    Attention, tu dois donner un pointer sur un dword contenant le masque, pas le dword lui même

    DWORD mask=0x3;
    SetThreadAffinityMask(threadID, &mask);

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    Super merci Nirgal76. Ça parait assez simple à utiliser.

    Petites précisions :

    Ta fonction s'utilise dans la definition du thread ou dans le code qui lance le thread ?

    sur le ThreadID. Si je lance mon thread comme cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void __fastcall Tecran_essai::startClick(TObject *Sender)
    {
     
            chrono = new ThChrono(false);
     
    }
    Quel est le threadID (handle) ?

    //+++++++++++++++++++++++++++++++++++++++

    Pour la suite c'est plus un problème d'utilisation du thread que je rencontre. Mon premier code fonctionne mais j'aimerai que le label récupérant le temps chrono ne soit pas écrit en dur dans le thread. J'aimerai donc pouvoir spécifié à la création du thread où il doit écrite la donnée lors de la synchronisation. Voici donc le code que j'ai fait :

    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
    #ifndef chronometreH
    #define chronometreH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    //---------------------------------------------------------------------------
    class ThChrono : public TThread
    {
    private:
    protected:
            void __fastcall Execute();
            void __fastcall AffMessage();
     
    public:
            __fastcall ThChrono(bool CreateSuspended,AnsiString *data);
            AnsiString *Thdata;
     
            LARGE_INTEGER  start;      //!< The start time of the chronometer
            LARGE_INTEGER  tic;
            LARGE_INTEGER  FQPF;
     
            bool           HRPCAvail;  //!< Is there an available HRPC
     
            AnsiString millit;
            double result;
    };
    //---------------------------------------------------------------------------
    #endif
    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
    __fastcall ThChrono::ThChrono(bool CreateSuspended,AnsiString *data)
            : TThread(CreateSuspended)
    {
            Thdata = data;
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::Execute()
    {
     
            HRPCAvail=QueryPerformanceCounter(&start); //memo du temps de start
            if (!HRPCAvail)   //si le compteur n'était pas disponible
            {
              start.LowPart = ::GetTickCount();   //basse resolution
              start.HighPart = 0;
            }
     
            while (!Terminated)
            {
               if (HRPCAvail) //si le compteur haute resolution était dispo
               {
                 QueryPerformanceCounter(&tic); //recup du temps
     
                 QueryPerformanceFrequency(&FQPF); //recup de la frequence
     
                 //resultat en msec
                 result=static_cast<double>(tic.QuadPart - start.QuadPart) * 1000
                  /static_cast<double>(FQPF.QuadPart);
               }
               else //si le compteur n'était pas disponible
               {
                 tic.LowPart = ::GetTickCount();
                 tic.HighPart = 0;
     
                 result = 0;
                 //resultat
                 result=tic.LowPart - start.LowPart;
     
               }
               millit = AnsiString(result);
               Synchronize(AffMessage);
            }
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::AffMessage()
    {
           *Thdata = millit;
    }
    Avec l'appel du thread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void __fastcall Tecran_essai::startClick(TObject *Sender)
    {
            chrono = new ThChrono(false,&(Label1->Caption));
    }
    Ça compile bien mais j'ai un bel access violation à l'exécution et c'est visiblement lors de l'exécution de la fonction du thread AffMessage().
    Une idée sur le pourquoi du comment?

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    Un petit up car j'ai toujours mon problème.

  5. #5
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 41
    Par défaut
    Bonjour, tu passe quoi en paramètre à ton Thread ?

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 057
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 057
    Par défaut
    C'est surprenant que cela compile !
    tu ne peux pas passer une propriété (Caption) en paramètre var (* ou &), cela contournerait les accesseurs défini par __property !
    En Delphi, ça ne compilerait pas du tout ! le C++ se laisse berner !

    le plus propre serait de définir un Evènement dans lequel tu fournis le nouveau libellé, lancer par Synchronize évidemment !

    Quel est le threadID (handle) ?
    tu as une propriété Handle et ThreadID sur l'objet TThread, c'est cela que tu parles ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Membre très actif Avatar de nirgal76
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2007
    Messages
    923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 923
    Par défaut
    Utilise la propriété Handle de TThread pour avoir le handle necessaire à setThreadAffinityMask.
    La propriété ThreadId va retourner l'ID ce qui est différent :
    Code de la VCL de TThread à ce sujet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        FHandle := Windows.GetCurrentThread;
        FThreadId := Windows.GetCurrentThreadId;
    Donc dans ton thread tu utiliseras:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SetThreadAffinityMask(Handle,&mask);
    ou si tu aime l'API
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SetThreadAffinityMask(GetCurrentThread(),&mask);

    Pour ton caption, passe plutot un pointeur sur le TLabel à ton constructeur
    tu défini une donnée membre private de ton Thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    private:
      TLabel* mLabel;
    Ton constructeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    __fastcall ThChrono(bool CreateSuspended, TLabel* pLabel)
    {
      mLabel=pLabel;
    ...
    }
    et dans un Synchronize tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    mLabel->Caption=....
    Pour l'appel du thread:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void __fastcall Tecran_essai::startClick(TObject *Sender)
    {
            chrono = new ThChrono(false, Label1);
    }

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    Salut à tous et merci pour vos réponses.

    Je viens d'essayer la méthode de Nirgal76. je pensais que l'utilisation de composants visuels comme un TLabel était impossible avec les thread car ils n'ont pas de "visuel".
    La méthode marche pour un appel du thread mais dès que je veux en lancer 2 en simultané le programme "Freeze". En passant par le debugger, je peux voir que les 2 threads semblent s'exécuter mais sur le programme principal plus rien ne répond : action sur les boutons impossible, affichage des 2 labels chrono immobiles.
    Pour ce qui est du ThreadAffinityMask, j'ai tout mis en commentaire car ça ne compile pas.

    voici le code.

    l'appel des 2 thread (les 2 chronos) :

    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
    void __fastcall Tecran_essai::start1Click(TObject *Sender)
    {
            chrono[1] = new ThChrono(false,Label1);
    }
    //---------------------------------------------------------------------------
     
    void __fastcall Tecran_essai::stop1Click(TObject *Sender)
    {
            chrono[1]->Terminate();
    }
    //---------------------------------------------------------------------------
     
     
    void __fastcall Tecran_essai::start2Click(TObject *Sender)
    {
            chrono[2] = new ThChrono(false,Label2);
    }
    //---------------------------------------------------------------------------
     
    void __fastcall Tecran_essai::stop2Click(TObject *Sender)
    {
            chrono[2]->Terminate();
    }
    //---------------------------------------------------------------------------
    Le cpp du chrono :

    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
    #include <vcl.h>
    #pragma hdrstop
     
    #include "chronometre.h"
    #include "page_essai.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
     
    __fastcall ThChrono::ThChrono(bool CreateSuspended,TLabel* pLabel)
            : TThread(CreateSuspended)
    {
            mLabel=pLabel;
     
            //DWORD mask=0x3;
     
            //DWORD STAM;
            //STAM = SetThreadAffinityMask(Handle, &mask);
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::Execute()
    {
     
            HRPCAvail=QueryPerformanceCounter(&start); //memo du temps de start
            if (!HRPCAvail)   //si le compteur n'était pas disponible
            {
              start.LowPart = ::GetTickCount();   //basse resolution
              start.HighPart = 0;
            }
     
            while (!Terminated)
            {
               if (HRPCAvail) //si le compteur haute resolution était dispo
               {
                 QueryPerformanceCounter(&tic); //recup du temps
     
                 QueryPerformanceFrequency(&FQPF); //recup de la frequence
     
                 //resultat en msec
                 result=static_cast<double>(tic.QuadPart - start.QuadPart) * 1000
                  /static_cast<double>(FQPF.QuadPart);
               }
               else //si le compteur n'était pas disponible
               {
                 tic.LowPart = ::GetTickCount();
                 tic.HighPart = 0;
     
                 result = 0;
                 //resultat
                 result=tic.LowPart - start.LowPart;
     
               }
               millit = AnsiString(result);
               Synchronize(AffMessage);
               //Thdata = &AnsiString(result);
            }
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void __fastcall ThChrono::AffMessage()
    {
           mLabel->Caption= millit ;
    }
    et le .h :

    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
    #ifndef chronometreH
    #define chronometreH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    //---------------------------------------------------------------------------
    class ThChrono : public TThread
    {
    private:
            TLabel* mLabel;
    protected:
            void __fastcall Execute();
            void __fastcall AffMessage();
     
    public:
            __fastcall ThChrono(bool CreateSuspended,TLabel* pLabel);
            AnsiString *Thdata;
     
            LARGE_INTEGER  start;      //!< The start time of the chronometer
            LARGE_INTEGER  tic;
            LARGE_INTEGER  FQPF;
     
            bool           HRPCAvail;  //!< Is there an available HRPC
     
            AnsiString millit;
            double result;
    };
    //---------------------------------------------------------------------------
    #endif

  9. #9
    Membre très actif Avatar de nirgal76
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2007
    Messages
    923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 923
    Par défaut
    Oui bon, me suis arraché faut passer la variable "mask", pas sa référence "&mask".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            DWORD mask=0x3;
     
            DWORD STAM;
            STAM = SetThreadAffinityMask(Handle, mask);
    Pour le reste, pour l'instant, je vois déjà que tes thread tournent sans temps mort.
    Dans ton thread, dans le bloc while (!terminated), après le synchronize, insere un Sleep pour donner du temps cpu aux autres thread (y compris le thread principal.
    "Sleep(0);" peut suffire, sinon "Sleep(1);", enfin, à toi de voir le temps qu'il faut mettre en testant.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    Bravo pour le sleep(1); c'est du bon sens... J'avais déjà eu ce type de problème avec des boucles while sous LabView sur du FPGA. Si tu ne donne pas de temps pour souffler un peu le reste du process ne peut plus s'exécuter. Cela marche au poil.

    Par contre la fonction SetThreadAffinityMask ne compile toujours pas car il me dit que Handle (propriété du thread) est un unsigned int et qu'il attends un void...

  11. #11
    Membre très actif Avatar de nirgal76
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2007
    Messages
    923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 923
    Par défaut
    Alors fait le avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SetThreadAffinityMask(::GetCurrentThread(),mask);
    ça au moins c'est sur que ça marche (ici ça compile en BCB 2010)

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Par défaut
    ok ça compile!

    Merci

  13. #13
    Membre à l'essai
    Inscrit en
    Novembre 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Novembre 2010
    Messages : 6
    Par défaut un Thread qui lance un autre thread
    slt à toutes et à tous,
    Je suis entrain de programmer une application qui doit exécuter 2 threads en même temps (avec c++builder). mais le premier thread doit faire une itération ensuite il lance le deuxième thread.


    pour cela dans le programme principale, j'utilise la fonction Resume(); pour lancer le premier thread . et dans le corps du premier thread j'utilise aussi Resume(); pour lancer le deuxieme.

    Néanmoins, lorsque je lance mon application, je m'aperçois que le thread 1 fonctionne bien mais que le 2 n'est pas activé. Il s'active uniquement lorsque le 1 se termine.
    donc pas de parallélisme , je ne sais pas est ce que je doit ajouter quelque chose

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

Discussions similaires

  1. TThread : EAccesViolation + EOSError
    Par Rodrigue dans le forum C++Builder
    Réponses: 12
    Dernier message: 09/01/2004, 15h19
  2. TThread et execl
    Par sebpatu dans le forum C++Builder
    Réponses: 2
    Dernier message: 17/11/2003, 00h02
  3. TThread et waitfor - descripteur non valide
    Par code34 dans le forum Langage
    Réponses: 2
    Dernier message: 27/10/2003, 23h44
  4. TThread: probleme de recuperation du Handle
    Par code34 dans le forum Langage
    Réponses: 8
    Dernier message: 07/09/2003, 03h04
  5. [TTHREAD] ne termine pas sont exécution
    Par Bbenj dans le forum Langage
    Réponses: 4
    Dernier message: 02/08/2002, 16h42

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