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

Delphi Discussion :

Alternative au sleep dans un thread


Sujet :

Delphi

  1. #1
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut Alternative au sleep dans un thread
    Bonjour,

    J'ai créé un thread qui contient une boucle repeat until terminated dans la procédure execute.
    Dans ce cas, le temps processeur de l'application monte à 30% (sur ma machine)

    Dès qu'on ajoute un sleep(1) dans la boucle, le temps descend à zéro mais la cadence du thread est drastiquement réduit (forcément on attend pendant théoriquement 1 ms, ce qui est énorme en regard des capacités du processeur)
    Je cherche une alternative, une fonction qui occuperait moins de temps mais qui rend la main aux autres processus dans windows afin de réduire considérablement le temps processeur.
    J'ai essayé Yield, ou encore SpinWait mais rien n'y fait.

    Merci pour vos conseils.

    Franck

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 812
    Points : 34 624
    Points
    34 624
    Billets dans le blog
    54
    Par défaut
    un Synchronize bidon ?
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  3. #3
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Bah non,
    Je viens de faire le test d'un synchronize qui ne fait absolument rien, et c'est encore pire, l'occupation processeur monte jusqu'à 45%.

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    12 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 12 038
    Points : 21 149
    Points
    21 149
    Par défaut
    Sleep(0) suffit pour forcer un relâchement du thread
    A lire : sleep avec une valeur inférieure à 1ms
    L'ordonnanceur même en l'absence de sleep va répartir du temps CPU pour les autres threads et process, cela en fonction de leur priorité.

    Sinon, TEvent permet de faire une pause dans un thread et de le réveiller au moment opportun (ou après un time out)

    Quel est le but de la boucle ?
    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

  5. #5
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Le sleep(0) ne change rien, toujours 30% de CPU.
    L'appel à Application.ProcessMessages non plus.
    Dès que je mets sleep(1), ça passe direct à 0% de charge CPU
    Le but est de faire de l'acquisition de données en TCP/IP avec un instrument de mesure.
    Je dois faire cette acquisition à une fréquence de moins d'1ms pendant une durée donnée, donc j'arrive à obtenir ce que je veux mais au détriment du temps CPU, et je n'aime pas ça pour la stabilité du système surtout que j'ai un superviseur qui ne doit pas être impacté.
    Le sleep(1) fait en réalité 2ms et n'est pas précis. Je ne sais pas pour quelle raison !
    J'avais déjà remarqué ce problème de 2ms lors du passage d'un OS à l'autre (Je crois qu'avec XP on avait bien les 1ms), mais avec Windows 10, je l'observe systèmatiquement.
    J'obtiens plus de précision en ajoutant cette fonction TimeBeginPeriod(1); de l'unité MMSystem, là le temps de 2ms est constant avec un sleep(1).
    Idem si je compile en 32 bits ou 64 bits.

    Mais je ne comprends pas qu'on ne puisse pas descendre en dessous de la milliseconde sans "Exploser" le temps CPU.

  6. #6
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Voici un projet d'exemple qui permet de mettre en évidence ce problème de sleep(1) qui ne fait pas 1ms.

    D'ailleurs il fait 16.66ms
    Sauf si on rajoute la fonction de l'unité MMSystem, ça passe à 2ms.
    Donc dans cet exemple, mettez en commentaire la ligne TimeBeginPeriod(1) et vous verrez que le temps passe à 16.66ms.
    Fichiers attachés Fichiers attachés

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    12 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 12 038
    Points : 21 149
    Points
    21 149
    Par défaut
    Je ne comprends pas cette façon de lire le TCP\IP, un Thread de lecture dédié et un WaitForData serait bien plus performant

    Et mesurer des temps court ça se fait un PerformanceCounter voir TStopWatch

    le Sleep(1) faisait presque toujours 2ms c'était déjà le cas en D7 sur Windows XP, je l'évoquais en 2010
    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

  8. #8
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    non, le problème ne se situe pas à la récèption des données.
    L'appareil fonctionne en polling.
    Ce sont les requètes que je synchronise.

  9. #9
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Et je confirme que le programme de teste que j'ai joint affichait bien 1000 sur XP, donc 1ms avec le sleep(1). (Tests effectués vers 2012/2014), je ne sais plus à quelle version de delphi on en était à l'époque, peut-être XE2)

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    12 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 12 038
    Points : 21 149
    Points
    21 149
    Par défaut
    On passe donc d'acquisition de données à de l'émission, ce n'est pas clair
    Tient le problème de Sleep(0) et le polling, déjà en 2003 j'en parlais, c'était pas facile d'avoir un 80ms précis sur Win2000 alors vouloir cadencer à 1ms

    As-tu pensé à changer la priorité de ton thread d'émission ?
    Car je n'ai jamais vu de D5 à D10, aucun Sleep(1) qui durait 1ms, cela pouvait arriver mais tu pouvais avoir des pics à 1,995ms assez fréquemment pour te faire rater un cycle
    Il faut aussi prendre en compte le temps d'émission, donc si tu veux un envoi tous les 1ms, tu dois retrancher le temps de la dernière émission, tu es donc obligé sur des délais si court, faire un Sleep(0) et attendre que le délai restant entre T-1 et T soit écoulé.
    Si tu veux faire du temps réel, tu dois même anticiper le temps d'exécution des opérations préliminaires à l'émission (ou les pré-calculer au cycle précédent), évidemment, on ne parle jamais en temps mais en nombre de cycle processeur ... Windows c'est pas fait pour du vrai temps réel.
    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

  11. #11
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    On passe donc d'acquisition de données à de l'émission, ce n'est pas clair
    non, c'est de l'acquisition en polling c'est à dire en Requete/réponse

    Je viens de faire des tests avec la même version compilé du programme de test que j'ai partagé (en 32 bits) et voici les résultats:

    J'ai trois vieilles machines en multi-boot XP/Windows 7.

    Le sleep(1) est à 1ms sur un seul OS de l'époque (windows 7) d'une des machines. Il s'agit d'un Windows 7 Ultimate 2009 service Pack 1.
    Le compteur de mon soft de test affiche une valeurs qui oscille autour de 980/985.
    Sur cette même machine, il y a aussi XP, et là le sleep(1) est à 2ms soit une valeur affichée autour dans les 510/517 (d'ailleurs, supérieur à 500 !)
    Il faut aussi prendre en compte le temps d'émission, donc si tu veux un envoi tous les 1ms, tu dois retrancher le temps de la dernière émission, tu es donc obligé sur des délais si court, faire un Sleep(0) et attendre que le délai restant entre T-1 et T soit écoulé.
    Oui tout à fait, c'est exactement ce que je fais, je ne tiens pas compte du temps du sleep mais je me base sur l'horloge calendaire qui, elle, tient bien la résolution de la ms et comme tu dis, j'attends que le prochain timing soit atteint avant de relancer une requête. Ca marche très bien, c'est très performant et très fiable si je ne mets pas de sleep, j'obtiens ce que je veux mais ça "bouffe" trop de processeur.

    Windows c'est pas fait pour du vrai temps réel.
    Bah oui, on n'est d'accord, Unix est bien plus adapté pour ça, mais je n'ai pas le choix. Windows n'est pas préemptif, même s'il y a des contournements pour y arriver mais je ne souhaite pas en arriver là.

  12. #12
    Expert confirmé
    Homme Profil pro
    Responsable informatique, développeur tout-terrain
    Inscrit en
    juin 2004
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable informatique, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juin 2004
    Messages : 879
    Points : 4 285
    Points
    4 285
    Par défaut
    Citation Envoyé par franckcl Voir le message
    non, c'est de l'acquisition en polling c'est à dire en Requete/réponse

    Je viens de faire des tests avec la même version compilé du programme de test que j'ai partagé (en 32 bits) et voici les résultats:

    J'ai trois vieilles machines en multi-boot XP/Windows 7.

    Le sleep(1) est à 1ms sur un seul OS de l'époque (windows 7) d'une des machines. Il s'agit d'un Windows 7 Ultimate 2009 service Pack 1.
    Le compteur de mon soft de test affiche une valeurs qui oscille autour de 980/985.
    Sur cette même machine, il y a aussi XP, et là le sleep(1) est à 2ms soit une valeur affichée autour dans les 510/517 (d'ailleurs, supérieur à 500 !)

    Oui tout à fait, c'est exactement ce que je fais, je ne tiens pas compte du temps du sleep mais je me base sur l'horloge calendaire qui, elle, tient bien la résolution de la ms et comme tu dis, j'attends que le prochain timing soit atteint avant de relancer une requête. Ca marche très bien, c'est très performant et très fiable si je ne mets pas de sleep, j'obtiens ce que je veux mais ça "bouffe" trop de processeur.


    Bah oui, on n'est d'accord, Unix est bien plus adapté pour ça, mais je n'ai pas le choix. Windows n'est pas préemptif, même s'il y a des contournements pour y arriver mais je ne souhaite pas en arriver là.
    Le problème du Sleep(1) dans un thread c'est que tu redonne la main au système (à l'ordonnanceur) pour 1 ms (au moins) mais rien ne garanti que celui-ci redonne le contrôle à ton thread pile 1 ms après... Tout dépend des autres process qui tournent sur la machine.

    Maintenant : Il est possible de faire des pauses de moins d'une millisecondes (j'avais un code pour ça, je le cherche, si le retrouve je le soumettrai ici)

    La syncapi de Windows permet aussi de créer des timers en microsecondes ce serai peu être la solution.

    Après comme l'on a pas d'extraits de ton code, il est difficile de te guider sur ce que tu pourrais améliorer ou pas...

    Et puis d'expérience comme d'autres l'ont dit il est très difficile d'avoir un cadencement régulier des threads sous Windows du fait qu'ils ne sont pas préemptifs mais tu devrai pouvoir jouer avec la priorité du ton thread (ça devrai améliorer un peu, ou du moins rendre plus reproductible le cadencement), voir ici : https://docs.microsoft.com/en-us/win...ing-priorities

  13. #13
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    novembre 2002
    Messages
    8 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2002
    Messages : 8 071
    Points : 26 119
    Points
    26 119
    Par défaut
    si ta CPU monte à cause de ton thread c'est qu'il boucle sans condition

    pour de la lecture de socket, tu peux utiliser un socket bloquant qui ne prendra rien en CPU tant que rien n'est à lire

    et si tu veux pouvoir gérer un timeout il faut passer par un select()
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  14. #14
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Citation Envoyé par sergio_is_back Voir le message
    Le problème du Sleep(1) dans un thread c'est que tu redonne la main au système (à l'ordonnanceur) pour 1 ms (au moins) mais rien ne garanti que celui-ci redonne le contrôle à ton thread pile 1 ms après... Tout dépend des autres process qui tournent sur la machine.
    Maintenant : Il est possible de faire des pauses de moins d'une millisecondes (j'avais un code pour ça, je le cherche, si le retrouve je le soumettrai ici)
    La syncapi de Windows permet aussi de créer des timers en microsecondes ce serai peu être la solution.
    Après comme l'on a pas d'extraits de ton code, il est difficile de te guider sur ce que tu pourrais améliorer ou pas...
    Et puis d'expérience comme d'autres l'ont dit il est très difficile d'avoir un cadencement régulier des threads sous Windows du fait qu'ils ne sont pas préemptifs mais tu devrai pouvoir jouer avec la priorité du ton thread (ça devrai améliorer un peu, ou du moins rendre plus reproductible le cadencement), voir ici : https://docs.microsoft.com/en-us/win...ing-priorities
    Dans mon tiroir, j'ai aussi un équivallent au GetTickCount que j'ai appellé GetCPUCountus et donc le résultat est en micro secondes.
    Voilà le code si ça peut intéresser quelqu'un:
    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
    type TTimeStamp= record case byte of
                     1: (Whole: int64); // Whole: comp
                     2: (Lo, Hi: Longint);
                   end;
    procedure getCPUticks(var TimeStamp:TTimeStamp);assembler;
      asm
        RDTSC; //db $0F; db $31;
        mov [TimeStamp.Lo], eax
        mov [TimeStamp.Hi], edx
    end;
    //---------------------------
    Function GetCPUCountus:int64;
    var TimeStamp:TTimeStamp;
    Begin
      getCPUticks(TimeStamp);
      result:=TimeStamp.Whole;
    end;
    Donc ça peut effectivement être utilisé pour un timer précis.
    Mais ma question est surtout de savoir comment rendre la main à Windows tout comme un sleep le fait mais en moins de temps afin de diminuer le temps CPU.

  15. #15
    Membre averti Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    septembre 2004
    Messages
    442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : septembre 2004
    Messages : 442
    Points : 353
    Points
    353
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    si ta CPU monte à cause de ton thread c'est qu'il boucle sans condition
    pour de la lecture de socket, tu peux utiliser un socket bloquant qui ne prendra rien en CPU tant que rien n'est à lire
    et si tu veux pouvoir gérer un timeout il faut passer par un select()
    Ce n'est pas la lecture de socket qui me pose problème, c'est l'envoi d'une requête à un moment bien précis, à savoir toutes les 2 ms. Sinon, je suis en mode non blocking et je n'ai pas de problème avec ça, le mode blocking peut être genant dans certaines conditions comme lors de la deconnexion d'un port physiquement à la volée, ça pose des problèmes de gestion des times out que j'ai pu résoudre en non blocking.

  16. #16
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    novembre 2002
    Messages
    8 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2002
    Messages : 8 071
    Points : 26 119
    Points
    26 119
    Par défaut
    en fait Windows n'est pas un OS temps réel, donc tu vas avoir un pb pour travailler à la ms près
    https://www.developpez.net/forums/d7...-sous-windows/

    Windows CE serait temps réel
    https://fr.wikipedia.org/wiki/Windows_CE
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

Discussions similaires

  1. Problème avec Thread.sleep() dans JavaFX
    Par Zyxcel314 dans le forum JavaFX
    Réponses: 5
    Dernier message: 10/05/2019, 13h57
  2. [Python 3.X] la fonction time.sleep( ) est inefficace dans mon thread
    Par éternel apprenant dans le forum Programmation multimédia/Jeux
    Réponses: 8
    Dernier message: 03/03/2019, 16h54
  3. Thread.sleep dans for()
    Par JackDannyL dans le forum Android
    Réponses: 13
    Dernier message: 13/01/2014, 23h09
  4. Thread sleep dans une boucle
    Par Sharcoux dans le forum Général Java
    Réponses: 7
    Dernier message: 17/03/2013, 19h29
  5. ce que fait sleep dans un thread
    Par ikuzar dans le forum Débuter
    Réponses: 2
    Dernier message: 26/08/2009, 09h00

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