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 :

Controle de processus [Débutant]


Sujet :

C

  1. #1
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut Controle de processus [Débutant]
    Salut les C,
    je n'arrive pas a contrôler les processus créer avec un|des appels a fork(),
    Le problème réside dans l'arrêt des processus et de reprise de contrôle par le processus parent.
    Je suppose, a tord, que si je lance un nouveau processus (dans un bloque conditionnel):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if ((child_pid=fork()) != -1) { 
      //le processus fils exécute son code puis retourne
      return 0 ;
    }
    et que celui ci exécute son code puis retourne, le processus parent reprend le contrôle et le processus fils est arrêter, seulement d'après mes expérience ce n'est pas le cas:
    le processus parent ne reprend pas le contrôle et si je termine pas le processus fils le code est exécuter doublement (vérifiable par un appel a printf() exécuter plusieurs fois).
    Prenons l'exemple suivant (que j'espère que vous ne jugerai pas immoral et que vous prendrez avec humours) afin que vous puissiez me guider:
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <time.h>
    #include <signal.h>
     
    int main() {
      pid_t child_1,child_2 ;
      pid_t master ;
      int waiting ;
      time_t randseed ;
      time(&randseed) ;
      srand(randseed/8) ;
      waiting=rand() % 15 ;
      time_t wait_time_start ;
      time_t wait_time_end ;
      int waiting_time ;
      char *child_2_say="child_2 say: ";
      char *child_1_say="child_1 say: ";
      int c ;
     
      master=getpid() ;
     
     
      c=0 ;
      printf("master pid: %i\n",master) ;
      fork() ;
      child_1=getpid() ;
      fork() ;
      child_2=getpid() ;
      time(&wait_time_start) ;
      while ( c < waiting) {
        if ( getpid() == child_1 && (c == waiting-2 || c == waiting-1) ) {
          /* kill() ou return au choix pour finir le processuss */
          printf("child_1 killed\n") ;
          kill(child_1,SIGTERM) ;
          //return 0 ;          
        }
        else if ( getpid() == child_2 && (c == waiting-2 || c == waiting-1) ) {
          /* kill() ou return au choix pour finir le processuss */
          printf("child_2 killed\n") ;
          kill(child_2,SIGTERM) ;
          //return 0 ;
        }
        else if (getpid() == child_1) {
     
    	time(&randseed) ;
            srand(randseed/8) ;
            sleep(rand() % waiting) ;
    	printf("%s i wait %i seconds\n",child_1_say,rand() % waiting) ;
        }
     
        else if (getpid() == child_2) {
     
    	time(&randseed) ;
            srand(randseed/8) ;
    	sleep(rand() % waiting) ;
    	printf("%s i wait %i seconds\n",child_2_say,rand() % waiting) ;
        }
     
        sleep(1) ;
        c++ ;
     
      }
     
      /* cette partie n'est jamais exécuter
       * a moins d'enlever les appels a kill() et|ou return:
       * dans ce cas elle est exécuter 4 fois (voir appel a printf()) */ 
     
     
      time(&wait_time_end) ;
      waiting_time=difftime(wait_time_end,wait_time_start) ;
     
      printf("We have wait %i seconds\n",waiting_time) ;
      return 0 ;
     
    }
    Je comprend parfaitement que le code est exécuter plusieurs fois si il y a plusieurs processus mais pas pourquoi le processus père ne reprends pas le contrôle.
    J'ai essayer avec la fonction waitpid() sans succès.

    Je sais que le sujet n'est pas facile et je vous serai grandement reconnaissant de bien vouloir me donner des conseils afin d'éclairer mon ignorance sur le sujet.

    J'attends vos réponses éclairées avec impatience.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    Bonjour,

    Qu'entends-tu par "reprendre le contrôle" ?

    Quand tu fais un fork, le code qui suit est exécuté simultanément par deux processus : le père et le fils.

    Ensuite, il est possible pour le père d'attendre la fin d'un processus fils avec wait().

    Sinon, "l'humour" contenu dans ton code n'est pas utile à la compréhension de ce dernier et vu qu'il est (un peu) "douteux", je te conseillerais d'éditer pour l'enlever

  3. #3
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    J'ai laisser mon humours au vestiaires.
    Je voulais dire par reprendre le contrôle de pouvoir exécuter du code par un processus et d'avoir le contrôle sur qui fait quoi:
    -Pouvoir faire exécuter du code uniquement par le processus voulus.
    -Pouvoir stopper le processus voulus.
    -> Suite a quoi le processus parent continue: le problème dans le code exemple.
    Mais avec des appels a fork() je n'arrive pas a faire ce que je veut proprement et ca se mélange.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 589
    Points
    41 589
    Par défaut
    Les deux processus tournent en parallèle après le fork(); si tu veux en bloquer l'un ou l'autre, tu utilises des objets de synchronisation (sémaphores, etc.)

  5. #5
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Bonjour,

    à la lecture de ton code je m'aperçois que tu ne comprends pas comment fonctionne fork. Je ne vais pas débuguer ton programme car de toute façon il va falloir que tu le réécrives. Je vais néanmoins t'orienter vers des références qui vont te permettre de comprendre le fonctionnement de fork.

    Tout d'abord la man page de fork. La partie exemple te donne le squelette classique d'un appel à fork :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    pid_t   pid;
     
        pid = fork ();
     
        if (pid > 0) {
             /* Processus père      */
        } else if (pid == 0) {
             /* Processus fils      */
        } else {
             /* Traitement d'erreur */
        }
    Dans cet exemple qui est très succinct, tu vois que par rapport à ton essai infructueux :
    • le retour de l'appel à fork est mémorisé
    • il y a une gestion des erreurs
    • il y a une partie qui sera exécutée par le père et une par le fils


    Pour te donner un aperçu de «comment ça fonctionne» :
    1. tu lances ton programme = il existe en mémoire et est exécuté (c'est un processus)
    2. l'exécution arrive sur un appel à fork
      • l'OS duplique ton programme : il existe maintenant en deux exemplaire en mémoire (il y a deux processus)
      • les deux copies sont identiques et indépendantes (on simplifie dans un premier temps, car cette affirmation est fausse mais suffisamment correcte pour comprendre) à un détail près : la valeur de retour de fork. Dans une des copies elle vaut 0, cette copie est appelée Fils, dans l'autre est ne vaut pas 0, cette copie est appelée Père.
      • que ce soit dans le père ou dans le fils, la ligne qui suit l'appel à fork sera exécutée. C'est pourquoi il y a le test sur la valeur de retour de fork : c'est le seul moyen de savoir dans quelle copie on se trouve (0 -> on est dans le Fils, différent de 0 -> on est dans Père).


    Je pense que cette explication devrait répondre à la partie

    Je voulais dire par reprendre le contrôle de pouvoir exécuter du code par un processus et d'avoir le contrôle sur qui fait quoi:
    -Pouvoir faire exécuter du code uniquement par le processus voulus.
    Quant à la partie
    -Pouvoir stopper le processus voulus.
    Tu peux utiliser wait ou waitpid (il y a un lien vers leur man page dans le lien sur la man page de fork donné un peu plus haut).
    Tu peux aussi utiliser kill pour tuer le Fils (ou plus généralement lui envoyer un signal), ou tu peux communiquer avec lui en utilisant les IPC (inter process communication). Je t'encourage à chercher la man page de kill, et googler IPC pour avoir des exemples. Il y a plusieurs moyen de faire (plusieurs API, des approches différentes) mais je ne m'étendrai pas là-dessus car je me pose une question :

    tu utilises (un peu ... du moins dans l'intention affichée) les forks comme si tu utilisais des threads ... es-tu certain de ne pas confondre les deux ? Jette un coup d'oeil sur : Thread et fork.

  6. #6
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    Merci pour ces éclaircissements kwariz
    Je confond effectivement les fork() avec les thread (j'ai même essayer de faire communiquer 2 processus comme on fait communiquer des sockets) et je comprend pas encore l'utilité de fork() si celui crée une copie du processus comme tu l'a expliquer:
    -> Pour faire faire une tache au programme de manière synchrone il y a les threads.
    -> pour lancer une commande il y a les exec() ou system() qui correspondent a un appel a fork() puis un exec() a l'intérieur de celui-ci (corriger moi si je me trompe)

    Je crois qu'un thread a les même variables globale que le processus qui le lance alors qu'un fork() créer une nouvelle instance du processus qui le lance (Je sort ça des modes de fonctionnement d'apache qui peut fonctionner en mode thread, en mode fork ou les deux).

    Je pense que me donner un exemple d'utilité d'un fork() m'éclairerai.
    (Apache fait un fork() pour chaque client qui se connecte en même temps...)

    Concernant wait() et waitpid() j'ai essayer sans succès.
    J'ai toujours l'impression que je n'ai pas le contrôle de qui fait quoi avec les fork().

    Je vais me renseigner sur les IPC j'ai dans ma bibliothèque le livre de Blaess que je n'ai pas encore commencer car je suis encore débutant intermédiaire en C et que c'est peut-être pas encore le moment (ca fait que 5 mois et demi que je fait du C) et ce livre ne s'adresse pas aux débutants.

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 589
    Points
    41 589
    Par défaut
    Citation Envoyé par Luke spywoker Voir le message
    system() qui correspondent a un appel a fork() puis un exec() a l'intérieur de celui-ci (corriger moi si je me trompe)
    system() fait fork(), exec() et waitpid().
    popen() fait fork(), pipe() et exec().

    Je crois qu'un thread a les même variables globale que le processus qui le lance
    Le thread est le processus qui le lance. Il fait partie du processus, qui regroupe plusieurs threads (conceptuellement, du moins. Sous *n*x, selon les noyaux et les versions, ils peuvent en fait être implémentés avec des processus qui partagent la totalité de leur mémoire).

  8. #8
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    C'est une histoire un peu compliquée

    Pour donner une image un peu simplifiée sans s'attacher à un OS quelconque on peut dire que lorsque tu lances un programme l'OS va créer un processus et le scheduler (en gros 1 programme en cours d'exécution = 1 processus).
    Pendant longtemps il n'y avait que ça de disponible. C'est entre autre pourquoi les systèmes *nix ne disposaient que de fork pour créer un autre processus à partir d'un processus déjà tournant et pouvoir faire du paralęllisme. Une fois le processus dupliqué avec fork on peut si on le désire utiliser une fonction de la famille exec pour remplacer le code de ce nouveau processus par un autre code.
    Cependant c'est relativement lourd car un processus c'est très gros : il y a non seulement le code, mais les données, les ressources utilisées, où on en est dans l'exécution, ...
    Passer d'un processus à une autre demande donc à l'OS de sauver tout ça puis de charger toutes les informations d'un autre processus avant de pouvoir continuer ... ça prend du temps.
    C'est pourquoi les threads ont été inventés. La plus petite portion manipulable par l'OS n'est plus le processus mais le thread. On peut voir le thread comme un bout de processus allégé. L'OS va pouvoir passer d'un thread à un autre dans un même processus sans avoir à tout sauver, il ne sauve que le minimum (en gros la pile les registres et les variables locales au thread et marquées comme telle). Cela a apporté un gros gain de performances. Et cela a aussi apporté l'API pthread (=POSIX thread)
    Les threads c'est donc très utile si on reste dans le même processus et qu'on veut faire des traitements en parallèles.
    Le fork a toujours son utilité (chaque commande shell que tu écris provoque un fork en général ) pour pouvoir exécuter un autre processus.

    Donc maintenant quand tu lances un programme, ça crée un processus, dans ce processus il y a au moins un thread.
    C'est évidemment très schématisé mais c'est pour te donner une idée ... ne prend pas tout ce que j'ai écrit au pied de la lettre car c'est quand même un poil plus complexe
    Tu peux commencer par lire les pages wiki (qui ne sont pas parmi les meilleures, mais c'est un début de butinage) concernant les processus et les threads.

    Pour une utilisation type de fork on peut citer par exemple l'utilisation d'une commande externe dans ton programme -> tu as besoin de faire un ls, tu ne vas pas le recoder dans ton programme alors tu forkes, puis tu execes le ls : tu attends avec un wait qu'il finisse et tu t'es arrangé pour pouvoir en récupérer la sortie pour la traiter ensuite dans ton programme.

    Une utilisation type des threads pourrait être par exemple : tu as codé une fonction qui fait la somme des éléments d'un tableau d'entiers. Tu as un gros à tableau à sommer. Plutôt que de le faire dans ton thread principal (que je nomme P) tu vas diviser le boulot en deux et le faire faire par des threads (W1 et W2 avec W pour workers ...). Tu restes à l'intérieur de ton programme. P crée un premier thread W1 et lui donne comme boulot de sommer la première moitié du tableau puis en crée un second (W2) qui sommera la seconde moitié. P se met en attente de la fin des deux threads, récupère leur résultat et fait la somme finale.

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 410
    Points : 23 805
    Points
    23 805
    Par défaut
    Bonsoir,

    À mon tour de rajouter ma pierre à l'édifice. :-)

    Citation Envoyé par Luke spywoker Voir le message
    je comprend pas encore l'utilité de fork()
    fork() signifie « fourcher » et sert avant tout à faire naître un nouveau processus. Il se trouve que ce processus tout neuf est créé à partir de rien et que, donc, c'est au départ le clone exact du processus qui lui a donné vie. Il en reste que c'est un processus distinct qui, a priori, est complètement indépendant de son père. Il va également vivre sa propre vie et évoluer de son côté. C'est donc notamment avec fork() que l'on va lancer d'autres programmes.

    Ceci posé :
    • exec() est un appel système qui remplace l'image du processus courant par celle extraite d'un fichier exécutable et reprendre l'exécution depuis le début de cette nouvelle image. Les deux étapes (fork() et exec()) sont distinctes pour que le programmeur ait la main dessus, parce que l'on peut utiliser fork() à d'autres choses et parce que, parallèlement, on n'a pas forcément l'intention de forker quand on passe d'un programme à l'autre, spécialement si on veut conserver le même PID ;
    • system() n'est PAS un appel système. C'est une facilité définie par le C et incluse dans la bibliothèque standard qui permet d'envoyer un ordre au système d'exploitation et d'attendre qu'il ait fini. Autrement dit, ça appelle le shell par défaut et ça lui passe littéralement la chaîne entre guillemets, qu'elle soit correcte ou non.


    si celui crée une copie du processus comme tu l'a expliquer:
    -> Pour faire faire une tache au programme de manière synchrone il y a les threads.
    -> pour lancer une commande il y a les exec() ou system() qui correspondent a un appel a fork() puis un exec() a l'intérieur de celui-ci (corriger moi si je me trompe)
    « thread », de son côté, signifie « fil » et se réfère au « fil de de l'exécution », c'est-à-dire à son déroulement (comme au fil de l'eau). L'idée générale est de faire courir plusieurs fils d'exécution au sein du même programme, et donc dans le même contexte. Les threads sont donc initialement et avant tout un concept.

    C'est pratique par exemple lorsque tu gères une interface graphique avec un gros bouton « Démarrer le traitement » : c'est ton programme qui gère cette interface et qui se met en attente d'un événement utilisateur (un clic sur le bouton). Lorsque tu cliques, ton programme va aller appeler la fonction concernée qui va donc démarrer le gros travail… et ne te rendre la main que lorsque celui sera fini, ce qui signifie qu'entre temps, ton interface est complètement figée puisque ton programme est occupé à autre chose. C'est un comportement que l'on retrouve souvent sur les gros programmes mal réalisés et, au passage, ceci t'interdit la mise en place d'un éventuel bouton « annuler », ce qui n'arrange rien.

    Il est alors très appréciable de pouvoir lancer plusieurs fils d'exécution au sein du même programme : l'un d'eux appelle la fonction de travail pendant que l'autre retourne gérer l'interface, qui reste alors utilisable.

    J'insiste bien sur le fait qu'il s'agit de lancer deux fils au sein du même programme, donc en partageant le même code et le même espace mémoire. J'ajoute également qu'en principe, on doit être capable d'implémenter l'exemple ci-dessus sans avoir à y recourir : les systèmes d'exploitation réellement multitâches n'étant disponibles auprès du grand public que depuis une époque relativement récente (même après W95, on a continué à utiliser D.O.S. jusqu'à la fin des années 1990).

    Maintenant, pourquoi implémente-t-on si souvent les threads avec fork() ? Principalement parce que le standard UNIX ne les définit pas du tout (et également parce que fork() est d'un usage trivial, comparé aux pthreads qui demandent l'apprentissage d'une API). Cela a fait l'objet de plusieurs critiques du monde Windows envers Linux à l'époque, que l'on accusait de ne pas avoir de gestion native des threads.

    En réalité, la majeure partie de ce qui fait les caractéristiques d'un thread sont déjà implémentées par fork(). En particulier, le code reste le même tant qu'on n'a pas fait exec() et l'espace des données reste lui aussi partagé jusqu'à ce que l'un des processus y fasse une écriture. Et pratiquement dès le départ, Linux a mis en place son appel « clone() » permettant de créer de nouveaux processus en spécifiant explicitement ce qui doit être partagé ou pas.

    Au fond, tout le travail avait déjà été fait et il n'y avait donc pas lieu de distinguer les deux plus que ça. La seule chose qui donne l'impression que les threads Linux ou Posix n'en sont pas réellement est le fait que chaque thread possède son propre PID, ce qui fais un peu fouillis lorsque l'on fait un « ps ».

    Il restait que « clone() » est en soi à peine plus difficile que « fork() » mais est d'une part un appel spécifique à Linux et, d'autre part, peu pratique pour faire la gestion et la synchronisation des threads entre eux. Ce qu'il manquait, donc, c'était une bibliothèque dédiée proposant une interface propre pour faire tout cela et s'appuyant sur « clone() » pour les faire naître.

    C'est ce que Xavier Leroy s'était attaché à faire en écrivant LinuxThreads qui a été la bibliothèque de threads la plus utilisée sous Linux, bien qu'il en existasse d'autres.

    POSIX a fini par les normaliser officiellement et l'Open Group les a publiés également. La NPTL a été développée pour lier intimement leur interface aux capacités de Linux et c'est ainsi qu'elle est devenue la bibliothèque de threads officielle.

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

Discussions similaires

  1. [DB400][Débutant]comprendre la gestion des processus actif
    Par horalass dans le forum Autres SGBD
    Réponses: 8
    Dernier message: 12/12/2006, 10h26
  2. [Débutant] Recherche controle ActiveX
    Par Invité dans le forum MFC
    Réponses: 2
    Dernier message: 19/10/2005, 18h01
  3. Contrôle d'exécution de processus
    Par TB38570 dans le forum Linux
    Réponses: 3
    Dernier message: 07/12/2004, 10h39
  4. Controler un nombre de processus identiques.
    Par ditfau6 dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 24/05/2004, 17h21
  5. [débutant][control]SS_BITMAP
    Par vvidal80 dans le forum MFC
    Réponses: 6
    Dernier message: 13/01/2004, 16h00

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