Partage
  • Partager sur Facebook
  • Partager sur Twitter

Discussion Pere vers Fils : Processus

Processus discussion pere fils langage C

    28 janvier 2021 à 10:15:45

    Bonjour,

    je souhaite créer 3 processus fils qui affiche ce que le père leur envoie.

    Le père récupère le numéro du fils saisie au clavier par l'utilisateur et envoie "fils numero ... (numero du fils), Je suis ton pere" au fils choisi par l'utilisateur.

    Programme : 

    Je crée 3 tubes anonyme ! 

    Je crée 3 fils avec une boucle for() 

     Je teste dans cette boucle si le retour de fork()

      - Si retour == 0 :

         /*dans ce cas je suis dans le fils */  

      - Si retour > 0 :

        /*dans ce cas je suis dans le père*/

    Fin boucle for

    Mes problèmes :

    Dans le code des fils le read (qui permet de lire ce que lui envoie le pere) est bloquant. Si je debloque le read() le processus fils continue à s'executer, or il ne fait qu'un printf et ensuite il fait un exit(EXIT_SUCCESS) et donc il s'arrête. 

    Dans le code père si je fais un scanf (permettant de lire le numero que l'utilisateur a entré), le scanf sera executé à chaque fois qu'un fils sera crée, or moi je veux que le père discute avec ces fils uniquement quand tous les fils sont créés...

    -
    Edité par NATHdb 28 janvier 2021 à 12:06:11

    • Partager sur Facebook
    • Partager sur Twitter
      28 janvier 2021 à 11:12:03

      Bonjour,

      Visiblement il manque quelque chose dans ton message, il y a ni question, ni code.

      • Partager sur Facebook
      • Partager sur Twitter

      git is great because Linus did it, mercurial is better because he didn't.

        28 janvier 2021 à 11:26:03

        >Mes problèmes :

        > Dans le code des fils

        en effet. Où est-il ?

        -
        Edité par michelbillaud 28 janvier 2021 à 11:26:17

        • Partager sur Facebook
        • Partager sur Twitter
          28 janvier 2021 à 12:04:24

          Désolé oui je viens de le modifier !

          • Partager sur Facebook
          • Partager sur Twitter
            28 janvier 2021 à 12:09:23

            NATHdb a écrit:

            Dans le code des fils le read (qui permet de lire ce que lui envoie le pere) est bloquant. Si je debloque le read() le processus fils continue à s'executer, or il ne fait qu'un printf et ensuite il fait un exit(EXIT_SUCCESS) et donc il s'arrête. 


            Si le processus fils doit faire une chose plusieurs fois (attendre l'arrivée d'un truc dans le tuyau et afficher), ça serait logique qu'il exécute une boucle.

            -
            Edité par michelbillaud 28 janvier 2021 à 12:10:02

            • Partager sur Facebook
            • Partager sur Twitter
              28 janvier 2021 à 12:16:54

              D'accord mais une boucle c'est bloquant ! 

              Du coup si je fais une boucle dans le code fils, le premier fils va rentrer dans la boucle et le programme va se stopper ici...

              • Partager sur Facebook
              • Partager sur Twitter
                28 janvier 2021 à 13:20:32

                Ton problème se traite avec un select (chiant) ou poll (propre). Les fils écrivent/lisent sur leur descripteur, mais le père attend que un des trois a écrit. C'est exactement à ça que sert poll.

                Pour faire simple : je schématise, il faut compléter.

                struct pollfd children[3];
                
                // en imaginant que la fonction birth créé un pipe et fasse un fork :
                children[0].fd = birth();
                children[1].fd = birth();
                children[2].fd = birth();
                
                // ensuite on indique qu'on souhaite attendre pour de la lecture .
                children[0].events = children[1].events = children[2].events = POLLIN;
                
                // tu fais une condition jusqu'à ce que les enfants soient terminés.
                while (!jesus_returns) {
                    poll(children, 3, -1); // il faudrait vérifier le code de retour aussi.
                
                    if (children[0].revents & POLLIN)
                        // tu peux faire un read sur children[0].fd sans bloquer
                    // tester 1 et 2 aussi...
                }



                -
                Edité par markand 28 janvier 2021 à 13:23:20

                • Partager sur Facebook
                • Partager sur Twitter

                git is great because Linus did it, mercurial is better because he didn't.

                  28 janvier 2021 à 13:40:08

                  Je ne comprend pas très bien ces deux méthodes ...

                  • Partager sur Facebook
                  • Partager sur Twitter
                    28 janvier 2021 à 13:43:23

                    Pas forcement besoin de select, les trois fils peuvent écrire dans un tuyau de communication commun des fils vers le père.

                    Une boucle n'a rien de bloquant, d'où sort cette idée ?

                    Ce qui peut être bloquant c'est read.

                    On ne peut pas deviner ce que tu ne comprends pas, si tu ne nous montres pas  ce que  tu comprends.

                    -
                    Edité par michelbillaud 28 janvier 2021 à 13:47:26

                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 janvier 2021 à 14:37:28

                      Je vous montre tout d'abord mon comment je crée mes tubes. 

                      En réalité je fais un malloc car le nombre de fils choisis par l'utilisateur est passé en paramètre lors de l'exécution. Ainsi on ne sait pas combien de fils l'utilisateur souhaitent créés (Dans l'exemple de post j'ai dit "3 fils" pour simplifier votre compréhension).

                      J'ai donc créé une fonction qui fait un malloc et qui renvoie un pointeur (int**) car la première dimension correspond aux nombres de fils et la 2ème dimensions correspond au entrée lecture et écriture. En sachant que l'entrée lecture vaut "0" et l'entrée écriture vaut "1".

                      J'ai nommé mon pointeur pour chaque tube "pointeurPipe"

                      Par exemple, si le fils numéro 3 (2 en réalité car ca commence à 0) souhaite faire un read(), il devra utiliser son tube qui lui est dédié, soit le tube numéro 2, donc son file descriptor est pointeurPipe[2][0]  ( c'est à dire, 2 car c'est le troisième fils et 0 car il se connecte à l'entrée de lecture).

                      int** creation_pipe(int nb_pipe){
                      
                          int i,j;
                          int ** pointeurPipe; 
                      
                          /* initialisation de n pipe */
                          if( (pointeurPipe = (int**) malloc( nb_pipe * sizeof(int*) )) == NULL){
                              fprintf(stderr,"Erreur de malloc");
                              exit(EXIT_FAILURE);
                          }
                      
                          /* Création des 2 entrées pour chaque pipe */
                          for( i=0 ; i < nb_pipe ; i++){
                              *(pointeurPipe + i) = (int*) malloc ( 2 * sizeof(int) );
                          }
                      
                          /* Création des lecture et écrite pour chaque pipe */
                          /* pointeurPipe[i][0]
                          /* pointeurPipe[i][1]*/
                          for( i=0 ; i < nb_pipe ; i ++){
                              for( j=0 ; j < 2 ; j++ ){
                                  pointeurPipe[i][j] = j;
                              }
                          }
                      
                          return pointeurPipe;
                      }

                      A présent, je vous montre le code dédié à la création des fils :

                      for( i=0 ; i < nb_fils ; i++){
                      
                              /* Création d'un fils */
                              if( (pid = fork()) < 0 ){
                                  fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                  perror("Erreur : ");
                                  exit(EXIT_FAILURE);     
                              }
                      
                              if( pid == 0 ){
                                  /* on est dans le fils */
                                  fils(i, nb_fils, pointeurPipe);
                              }
                          
                              if( pid > 0) {
                                  
                                  /* on est dans le père */
                      
                                  /* update pid, je récupère le pid 
                                  des fils créé et les met dans un tableau */
                                  update_tab_pid(tab_pid,i,pid);
                      
                                  /* Le père attend vérifie la fin de chaque fils */
                                  if( (waitpid(pid ,&statut, 0)) != pid) { perror("Erreur lors de l'attente du fils "); exit(EXIT_FAILURE);}
                              
                                  if( WIFEXITED(statut) )
                                      printf("PERE : Le fils %d a termine ; valeur retournee = %d ; son PID : %d\n\n", i+1,WEXITSTATUS(statut), pid);
                                  else
                                      printf("Le fils %d a termine anormalement.\n", i+1);
                              }
                          } 

                      Puis voici la fonction dédié à chaque fils, chaque doit fils après sa création attendre un message venant du père puis affiche le message et s'arrête. 

                      Voici pour le moment mon code qui n'est pas fonctionnel, j'ai réussi à rendre le read() non bloquant grâce à fcntl() mais maintenant c'est ma boucle do while() qui empêche la création des autres fils, ici seul le premier fils est créé.

                      void fils(int num_fils, int nb_fils, int **pointeurPipe){
                      
                          int attributs, tmp, res;
                          
                          /* FCNTL : pour rendre le read non bloquant */
                          attributs = fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_GETFL);
                          fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_SETFL, attributs | O_NONBLOCK);
                      
                          printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                      
                          do{
                              res = read(pointeurPipe[num_fils][TUBE_LECTURE], &tmp, sizeof(int));
                              
                              if(res != -1){
                                  printf("J'ai rien recu encore...\n");
                                  sleep(1);
                              }
                      
                          }while((res == -1) && (errno == EAGAIN));
                      
                          printf("J'ai recu la valeur %d provenant du père \n", tmp);
                      
                          exit(EXIT_SUCCESS); 
                      }



                      -
                      Edité par NATHdb 28 janvier 2021 à 14:39:44

                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 janvier 2021 à 14:48:10

                        Pourquoi rendre le read non bloquant ?

                        Chaque processus fils doit ATTENDRE l'arrivée d'un message pour faire quelque chose ensuite. Ca s'appelle SE BLOQUER en attente.

                        Le fils n'a pas besoin de recevoir les descripteurs des DEUX bouts du tuyau. Ni le nombre de fils.

                        void fils (int numero, int fd) 
                        {
                            for(;;) {
                                  read(fd, ..... );
                                  printf( .....);
                            }
                        }
                        



                        -
                        Edité par michelbillaud 28 janvier 2021 à 14:52:09

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 janvier 2021 à 15:34:56

                          un read est bloquant, du coup si je le rend PAS non bloquant, tout mon programme se bloque lors du read() du premier fils...

                          Pour les descripteurs, étant donné que je créé mais N tubes (avec N = nombre de fils) AVANT de créer les fils avec fork(), les N tubes sont dupliqués à chaque fils créés, et donc les N fils ont accès au N tubes.

                          Je sais qu'il faut fermer l'écriture de tous les tubes pour tous les fils car les fils n'écrivent pas, ils font que lire les messages du père. Du coup j'avais pensé à faire :

                          for( j=0 ; j < nombre_fils ; j++){
                           
                           // on ferme le tube en écriture
                           // c'est l'indice "1"
                           close( pointeurPipe[j][1]);
                          
                          }

                          Je sais aussi que si ma théorie expliqué ci dessus avec la duplication est vraie. Il faut fermé toutes les entrées lecture de tous les tubes sauf celle du tube du fils courant.

                          for( j=0 ; j < nombre_fils ; j++){
                           
                           // on ferme le tube en lecture
                           // c'est l'indice "0"
                           // On ferme seulement les entrées lecture
                           // Des autres tubes pas celle du fils courant
                           if( j != numero_fils )
                              close( pointeurPipe[j][0]);
                          
                          }




                          -
                          Edité par NATHdb 28 janvier 2021 à 15:37:36

                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 janvier 2021 à 16:38:31

                            NATHdb a écrit:

                            un read est bloquant, du coup si je le rend PAS non bloquant, tout mon programme se bloque lors du read() du premier fils...

                            Quelle drôle d'idée.

                            Quant on fait un read "normal", ca bloque le processus qui fait le read, c'est à dire le fils. Personne d'autre.

                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 janvier 2021 à 16:45:18

                              NATHdb a écrit:

                              un read est bloquant, du coup si je le rend PAS non bloquant, tout mon programme se bloque lors du read() du premier fils...


                              Non. Seul le fils se bloque lui même. Les autres tournent à leur rythmes. La seule chose qui sera bloquante au niveau du processus parent c'est au moment de communiquer à du parent au fils (en écriture) si le parent n'a pas défini le descripteur en non bloquant. Le fils doit rester bloquant, c'est justement lui qui attend d'avoir du contenu pour travailler.

                              Si ton programme se fige parce qu'un des fils fait un read alors tu as mal codé quelque chose. C'est justement le principe de faire des fork, ne plus rien bloquer et laisser tourner des processus. C'est comme ça que sont implémentés openssh, sysvinit, etc.

                              -
                              Edité par markand 28 janvier 2021 à 16:48:42

                              • Partager sur Facebook
                              • Partager sur Twitter

                              git is great because Linus did it, mercurial is better because he didn't.

                                28 janvier 2021 à 17:05:55

                                Voila un exemple avec UN processus fils (je ne suis pas là pour faire les exercices)

                                #include <stdio.h>
                                #include <stdlib.h>
                                #include <sys/types.h>
                                #include <unistd.h>
                                #include <signal.h>
                                
                                void action_pere(int out);
                                void action_fils(int in);
                                
                                int main() {
                                
                                    int tuyau[2];    // permet au père d'écrire au fils.
                                    pipe(tuyau);     // écrire dans tuyau[1], lire dans tuyau[0]
                                
                                    pid_t pid_fils = fork();
                                    if (pid_fils) {
                                        // code du fils
                                        close(tuyau[1]);  // le fils ferme le bout qui sert à écrire dans le tuyau
                                        action_fils(tuyau[0]);
                                        exit(0);
                                    } 
                                
                                    // code du père
                                    close(tuyau[0]);  // le père ne lit pas dans le tuyau
                                    action_pere(tuyau[1]);
                                    kill(pid_fils, SIGTERM);
                                    
                                    return 0;
                                }
                                
                                void action_pere(int out) {
                                    sleep(1);
                                    write(out, "pim", 4);
                                    sleep(1);
                                    write(out, "pam", 4);
                                    sleep(1);
                                    write(out, "poum", 5);
                                    sleep(1);
                                }
                                
                                void action_fils(int in) {
                                    char chaine[20];
                                    for(;;) {
                                        read (in, chaine, 20);
                                        printf("* Le fils a lu : %s\n", chaine);
                                    }
                                };
                                


                                PS: le problème avec les cours de soi-disant "programmation système", c'est souvent que les exemples d'un intéret douteux sont programmés avec les pieds. Pas de découpage en fonctions, noms de variables affreux, etc.

                                PS2: en fait, la programmation système, c'est quand on écrit du logiciel qui n'est pas un programme "d'application", mais des utilitaires et bibliothèques qui servent à d'autres programmes. Ici ça n'a rien de plus "systeme" qu'un banal programme multi-threads en Java ou Python.

                                -
                                Edité par michelbillaud 28 janvier 2021 à 17:10:36

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  28 janvier 2021 à 17:07:06

                                  J'exécute ce code fils : 

                                  void fils(int num_fils, int nb_fils, int **pointeurPipe){
                                  
                                      int attributs, tmp, res;
                                      
                                      /* FCNTL : pour rendre le read non bloquant */
                                      attributs = fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_GETFL);
                                      fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_SETFL, attributs | O_NONBLOCK);
                                  
                                      printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                                  
                                      read(pointeurPipe[num_fils][TUBE_LECTURE], &tmp, sizeof(int));
                                  
                                      printf("J'ai recu la valeur %d provenant du père \n", tmp);
                                  
                                      exit(EXIT_SUCCESS); 
                                  }

                                  Le programme fonctionne normalement, il ne se bloque pas car j'ai fait appel à fcntl. voici ce que j'obtiens lorsque je crée 2 fils : 

                                  Lorsque je supprime la partie de fcntl, 

                                  void fils(int num_fils, int nb_fils, int **pointeurPipe){
                                  
                                      int tmp;
                                  
                                      printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                                  
                                      read(pointeurPipe[num_fils][TUBE_LECTURE], &tmp, sizeof(int));
                                  
                                      printf("J'ai recu la valeur %d provenant du père \n", tmp);
                                  
                                      exit(EXIT_SUCCESS); 
                                  }

                                  Voici ce que j'obtiens :

                                  Le fils 1 est bloqué au niveau de son read(), et le programme se bloque

                                  michelbillaud a écrit:

                                  Comment se fait il que tu exécutes le code fils en faisant "if( pid_fils ) "

                                  J'ai appris qu'on doit exécuter le code fils uniquement en faisant la condition pid == 0 :

                                  /* Création d'un fils */
                                          if( (pid = fork()) < 0 ){
                                              fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                              perror("Erreur : ");
                                              exit(EXIT_FAILURE);     
                                          }
                                  
                                          if( pid == 0 ){
                                              /* on est dans le fils */
                                              fils(i, nb_fils, pointeurPipe);
                                          }

                                  De plus, 

                                  j'ai appris que si le pid était supérieur à > 0 on était dans le père

                                  if( pid > 0) {
                                              
                                              /* on est dans le père */
                                  }

                                  Enfin le code qui était en dehors des 3 fils ci dessus, j'ai appris qu'il était exécuté par à la fois le fils et père...


                                  int main() {
                                  
                                      int tuyau[2];    // permet au père d'écrire au fils.
                                      pipe(tuyau);     // écrire dans tuyau[1], lire dans tuyau[0]
                                  
                                      pid_t pid_fils = fork();
                                      if (pid_fils) {
                                          // code du fils
                                          close(tuyau[1]);  // le fils ferme le bout qui sert à écrire dans le tuyau
                                          action_fils(tuyau[0]);
                                          exit(0);
                                      } 
                                  
                                      // code du père
                                      close(tuyau[0]);  // le père ne lit pas dans le tuyau
                                      action_pere(tuyau[1]);
                                      kill(pid_fils, SIGTERM);
                                      
                                      return 0;
                                  }
                                  

                                  -
                                  Edité par NATHdb 28 janvier 2021 à 17:23:40

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    28 janvier 2021 à 17:16:06

                                    A priori, il se bloque tant qu'il n'y a rien à recevoir, c'est à dire que personne n'a rien envoyé dans le pipe.

                                    Le problème serait peut être du côté du père.

                                    ---

                                    Pour l'allocation, tu t'enquiquines beaucoup.  Les descripteurs pour un pipe c'est deux entiers consécutifs en mémoire.

                                    1. Pour  n pipes, il suffit de réserver un tableau de 2*n entiers

                                    int *fd = malloc( 2 * n * sizeof(int));
                                    

                                    2. Les descripteurs du pipe numéro k seront en   fd[2*k] et fd[2*k + 1]

                                    3/ Pour les initialiser

                                    for (int k = 0; k < n; k++) {
                                       pipe(fd + 2*k);
                                    }
                                    


                                    Une cause de tes soucis : Dans ton code, tu n'appelles jamais pipe(), donc les descripteurs ne sont pas initialisés :

                                    tu n'as pas de tuyaux dans ton programme.



                                    -
                                    Edité par michelbillaud 28 janvier 2021 à 17:34:25

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      28 janvier 2021 à 17:25:33

                                      D'accord mais tu m'as dis 2 messages plus haut que ca bloque uniquement le processus qui fait le read(), or c'est le fils qui devrait se bloquer, pas tout le programme...

                                      Je vous envoie mon code, ca sera peut être plus simple : 

                                      AH DESOLE JE N AVAIS PAS VU TON NOUVEAU POSTE !

                                      Il est plutôt propre, il manque juste les close et le faire fonctionner avec le read()...

                                      #include <stdio.h>      /* Pour printf, fprintf, perror */
                                      #include <unistd.h>     /* Pour exit, EXIT_FAILURE, EXIT_SUCCESS et pipe*/
                                      #include <fcntl.h>
                                      #include <errno.h>
                                      #include <sys/types.h>   /* Pour pid_t */
                                      #include <sys/wait.h>   /* Pour wait */
                                      #include <stdlib.h>     /* Pour fork et malloc */
                                      
                                      
                                      #define TUBE_LECTURE 0
                                      #define TUBE_ECRTURE 1
                                      
                                      
                                      int** creation_pipe(int nb_pipe);
                                      void fermeture_pipe(int **pointeurPipe,int nb_pipe);
                                      void fils(int num_fils, int nb_fils, int **pointeurPipe);
                                      
                                      
                                      int main(int argc, char *argv[]){
                                          int i;
                                          pid_t pid;
                                          int statut;
                                          int nb_fils;
                                      
                                          int** pointeurPipe=NULL;
                                      
                                          pid_t* tab_pid=NULL;
                                          
                                          /* Vérification arguments commande */
                                          if( argc != 2 ){
                                              fprintf(stderr, "Usage: %s n\n", argv[0]);
                                              fprintf(stderr, "\tOu:\n");
                                              fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                              exit(EXIT_FAILURE);
                                          }
                                          if( ( atoi(argv[1]) < 1 ) || ( atoi(argv[1]) > 5 ) ){
                                              fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                              exit(EXIT_FAILURE);
                                          }
                                      
                                          /* Recuperation de l'argument nombre de fils */
                                          nb_fils = atoi(argv[1]);
                                      
                                          /* Création de n pipe */
                                          pointeurPipe = creation_pipe(nb_fils);
                                      
                                          /* Création d'un tableau de n pid */
                                          tab_pid = creation_tab_pid(nb_fils);
                                      
                                          for( i=0 ; i < nb_fils ; i++){
                                      
                                              /* Création d'un fils */
                                              if( (pid = fork()) < 0 ){
                                                  fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                                  perror("Erreur : ");
                                                  exit(EXIT_FAILURE);     
                                              }
                                      
                                              /* Programme du fils */
                                              if( pid == 0 )
                                                  fils(i, nb_fils, pointeurPipe);
                                      
                                              /* Programme père */
                                              if( pid > 0) {
                                                  
                                                  /* Verification de l'extinction de fils */          
                                                  if( (waitpid(pid ,&statut, 0)) != pid) { perror("Erreur lors de l'attente du fils "); exit(EXIT_FAILURE);}
                                              
                                                  if( WIFEXITED(statut) )
                                                      printf("PERE : Le fils %d a termine ; valeur retournee = %d ; son PID : %d\n\n", i+1,WEXITSTATUS(statut), pid);
                                                  else
                                                      printf("Le fils %d a termine anormalement.\n", i+1);
                                              }
                                          } 
                                          fermeture_pipe(pointeurPipe, atoi(argv[1]));
                                          free(pointeurPipe);
                                          pointeurPipe=NULL;
                                      }
                                      
                                      void fils(int num_fils, int nb_fils, int **pointeurPipe){
                                      
                                          int attributs, tmp, res;
                                          
                                          /* FCNTL : pour rendre le read non bloquant */
                                          /*attributs = fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_GETFL);
                                          fcntl(pointeurPipe[num_fils][TUBE_LECTURE], F_SETFL, attributs | O_NONBLOCK);*/
                                      
                                          printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                                      
                                          if( (read(pointeurPipe[num_fils][TUBE_LECTURE], &tmp, sizeof(int))) == -1 ){
                                              perror("Erreur read ");
                                              exit(EXIT_FAILURE);
                                          }
                                      
                                          printf("J'ai recu la valeur %d provenant du père \n", tmp);
                                      
                                          exit(EXIT_SUCCESS); 
                                      }
                                      
                                      int** creation_pipe(int nb_pipe){
                                      
                                          int i,j;
                                          int ** pointeurPipe; 
                                      
                                          /* initialisation de n pipe */
                                          if( (pointeurPipe = (int**) malloc( nb_pipe * sizeof(int*) )) == NULL){
                                              fprintf(stderr,"Erreur de malloc");
                                              exit(EXIT_FAILURE);
                                          }
                                      
                                          /* Création des 2 entrées pour chaque pipe */
                                          for( i=0 ; i < nb_pipe ; i++){
                                              *(pointeurPipe + i) = (int*) malloc ( 2 * sizeof(int) );
                                          }
                                      
                                          /* Création des lecture et écrite pour chaque pipe */
                                          /* pointeurPipe[i][0]
                                          /* pointeurPipe[i][1]*/
                                          for( i=0 ; i < nb_pipe ; i ++){
                                              for( j=0 ; j < 2 ; j++ ){
                                                  pointeurPipe[i][j] = j;
                                              }
                                          }
                                      
                                          return pointeurPipe;
                                      }
                                      
                                      void fermeture_pipe(int **pointeurPipe,int nb_pipe){
                                          int i;
                                      
                                          /* Liberation des n pipes */
                                          for ( i=0 ; i < nb_pipe ; i++){
                                              free(*(pointeurPipe + i));
                                              *(pointeurPipe + i) =NULL;
                                          }
                                      }



                                      -
                                      Edité par NATHdb 28 janvier 2021 à 17:39:42

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        28 janvier 2021 à 17:38:37

                                        Qu'est-ce qui te fait dire que TOUT le programme se bloque ?

                                        Visiblement, il n'y a rien qui marche, parce que les read et les write se font dans des descripteurs non initialisés, probablement parce que t'embrouiller dans les malloc (avec les complications de tableau 2D)  t'a fait oublier qu'ensuite il fallait ensuite appeler pipe() pour créer les tuyaux après avoir réservé de la place pour les descripteurs.

                                        -
                                        Edité par michelbillaud 28 janvier 2021 à 17:41:32

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          28 janvier 2021 à 17:59:48

                                          Pourquoi je crois qu'il bloque tout mon programme...? Car si les autres fils se créeraient, je verrai à l'écran FILS n°2, n°3 ... 

                                          Or là je vois : 

                                          Je suis repartis sur de meilleurs base, le read() bloque toujours mon programme.

                                          #include <stdio.h>      /* Pour printf, fprintf, perror */
                                          #include <unistd.h>     /* Pour exit, EXIT_FAILURE, EXIT_SUCCESS et pipe*/
                                          #include <fcntl.h>
                                          #include <errno.h>
                                          #include <sys/types.h>   /* Pour pid_t */
                                          #include <sys/wait.h>   /* Pour wait */
                                          #include <stdlib.h>     /* Pour fork et malloc */
                                          
                                          #define TUBE_LECTURE 0
                                          #define TUBE_ECRTURE 1
                                          
                                          void fils(int num_fils, int nb_fils, int * tube){
                                          
                                              int tmp;
                                          
                                              printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                                          
                                              if( (read( tube[ 2 * nb_fils ] , &tmp, sizeof(int))) == -1 ){
                                                  perror("Erreur read ");
                                                  exit(EXIT_FAILURE);
                                              }
                                          
                                              printf("J'ai recu la valeur %d provenant du père \n", tmp);
                                          
                                              exit(EXIT_SUCCESS); 
                                          }
                                          
                                          int main(int argc, char *argv[]){
                                              int i;
                                              pid_t pid;
                                              int statut;
                                              int nb_fils;
                                              int *tube=NULL;
                                             
                                              /* Vérification arguments commande */
                                              if( argc != 2 ){
                                                  fprintf(stderr, "Usage: %s n\n", argv[0]);
                                                  fprintf(stderr, "\tOu:\n");
                                                  fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                  exit(EXIT_FAILURE);
                                              }
                                              if( ( atoi(argv[1]) < 1 ) || ( atoi(argv[1]) > 5 ) ){
                                                  fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                  exit(EXIT_FAILURE);
                                              }
                                          
                                              /* Recuperation de l'argument nombre de fils */
                                              nb_fils = atoi(argv[1]);
                                          
                                          
                                          
                                              
                                              /* Initialisation nombre tube */
                                              tube = (int*) malloc( 2 * nb_fils * sizeof(int));
                                          
                                              for ( i=0 ; i < nb_fils ; i++ ) {
                                                  pipe( tube + 2 * i );
                                              }
                                          
                                          
                                          
                                              for( i=0 ; i < nb_fils ; i++){
                                          
                                                  /* Création d'un fils */
                                                  if( (pid = fork()) < 0 ){
                                                      fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                                      perror("Erreur : ");
                                                      exit(EXIT_FAILURE);     
                                                  }
                                          
                                                  if( pid == 0 ){
                                                      /* on est dans le fils */
                                                      fils(i, nb_fils, tube);
                                                  }
                                              
                                                  if( pid > 0) {
                                                      
                                                      /* on est dans le père */
                                          
                                                      if( (waitpid(pid ,&statut, 0)) != pid) { perror("Erreur lors de l'attente du fils "); exit(EXIT_FAILURE);}
                                                  
                                                      if( WIFEXITED(statut) )
                                                          printf("PERE : Le fils %d a termine ; valeur retournee = %d ; son PID : %d\n\n", i+1,WEXITSTATUS(statut), pid);
                                                      else
                                                          printf("Le fils %d a termine anormalement.\n", i+1);
                                                  }
                                              } 
                                          
                                              free(tube);
                                              tube=NULL;
                                          }
                                          
                                          

                                          -
                                          Edité par NATHdb 28 janvier 2021 à 18:03:14

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            28 janvier 2021 à 18:21:53

                                            Il ne faut passer à la fonction "fils" que les informations qui lui sont absolument nécessaires.

                                            Ca évitera les accidents comme celui-ci

                                            if( (read( tube[ 2 * nb_fils ]

                                            à remplacer par

                                            if( (read( tube[ 2 * num_fils ]

                                             =>  2*nb_fils était un indice hors tableau, contenant n'importe quoi. Comportement indéfini. Quand c'est 0, ça attend des trucs du clavier.

                                            Mieux

                                            void fils(int num_fils, int in){
                                            
                                                int tmp;
                                             
                                                printf("\nFILS : Je suis le fils n° %d \n", (num_fils + 1) );
                                            
                                                if( (read(in , &tmp, sizeof(int))) == -1 ){
                                               

                                            avec l'appel

                                            file( i, tube[2*i]);
                                            

                                            --------------------

                                            Dans la boucle

                                            1. le père lance un premier fils fork+if pid==0
                                            2. le père attend qu'il soit terminé waitpid

                                            donc il ne lancera le second que quand le premier sera terminé

                                            for( i=0 ; i < nb_fils ; i++){
                                                    pid = fork();
                                                    if( pid == 0 ){
                                                        fils(i, nb_fils, tube);
                                                    }
                                                 
                                                    if( pid > 0) {
                                                         
                                                        if( (waitpid(pid ,&statut, 0)) != pid) {....


                                            => une premiere boucle pour lancer tous les processus fils, une seconde pour attendre qu'ils soient tous terminés.

                                            ------------

                                             Par ailleurs, je ne vois pas le processus père faire des write dans les tuyaux.

                                             => les processus fils risquent d'attendre longtemps.

                                            -
                                            Edité par michelbillaud 28 janvier 2021 à 19:00:01

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              28 janvier 2021 à 18:57:05

                                              Comment faire alors pour que le père crée tous les processus et seulement après il fait ce que il a à faire ... ? 

                                              Oui je n'ai pas encore implémenté les write(), je souhaite d'abord que tous les fils soient prêt à recevoir un message...

                                              -
                                              Edité par NATHdb 28 janvier 2021 à 18:57:48

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                28 janvier 2021 à 19:02:07

                                                une premier boucle pour lancer les processus.
                                                ensuite on travaille avec

                                                et après une autre boucle pour attendre qu'ils soient terminés pour fermer boutique.

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  28 janvier 2021 à 19:07:54

                                                  Des problèmes de tyauterie?Voici un lien utile: http://www.zeitoun.net/articles/communication-par-tuyau/start Ici, je pense que c'est le père qui doit gérer les numéros de pipe (ou fd) de ses fils. Chaque fils lit sur son fd=0 et écrit sur son fd=1 ou fd=2 Le père aura des fd=3,4 5,6, 7,8 etc. Je n'ai pas vu de dup() ou dup2() qui me semble essentiel pour ces manipulartions. Je pense que l'utilisateur n'a pas besoin de connaître le pid des fils. Un simple numéro de 1 à N suffit. C'est le père qui doit connaître les pid de ses fils. À chaque fils dans le tableau, le père aura le pid' le fd pour écrire, le fd pour lire. Si rien n'est bloqué de l'extérieur, je ne vois pas pourquoi l'écriture du père vers ses fils serait bloquant. Les fils se mettent dans une boucle avec un read qui est bloquant pour eux mais pas pour le père. De même la lecture du père sur un fils ne sera bloquant que si le fils ne réagit pas (bug possible ...)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Le Tout est souvent plus grand que la somme de ses parties.

                                                    28 janvier 2021 à 19:12:54

                                                    PierrotLeFou a écrit:

                                                     Chaque fils lit sur son fd=0 et écrit sur son fd=1 ou fd=2


                                                    Je crois que tu confonds avec le lancement de programmes par les fonctions de la famille exec.

                                                    Les programmes utilisent les descripteurs 0 1 et 2 pour l'entrée standard etc.   et il faut effectivement rediriger les tuyaux pour connecter l'entrée de l'un avec la sortie de l'autre.

                                                    Mais là c'est un autre problème.

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      28 janvier 2021 à 19:31:36

                                                      Quand le père écrit sur son fd=1, il écrit à quel fils?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Le Tout est souvent plus grand que la somme de ses parties.

                                                        28 janvier 2021 à 20:52:21

                                                        Il y a eu de l'amélioration mais ce n'est pas fonctionnel à 100%. En effet, le père crée les fils puis récupère leur PID à chaque création et les met dans un tableaux.

                                                        Ensuite, le père demande à l'utilisateur d'entrer le numéro du fils à sélectionner pour envoyer un message. Puis il fait un write(). Le fils sélectionner reçoit l'information et affiche un message, puis il s'arrête. Enfin le père vérifie l'arrêt de chaque fils. (Pour l'instant je n'ai pas gerer l'arrêt des fils qui ne reçoit pas de message, eux ils sont encore attente, bloquer avec leur read() ). 

                                                        Cependant je souhaite envoyer au fils la valeur de la variable tmp soit "10". Toutefois, le fils affiche une valeur aléatoire...

                                                        #include <stdio.h>      /* Pour printf, fprintf, perror */
                                                        #include <unistd.h>     /* Pour exit, EXIT_FAILURE, EXIT_SUCCESS et pipe*/
                                                        #include <fcntl.h>
                                                        #include <errno.h>
                                                        #include <sys/types.h>   /* Pour pid_t */
                                                        #include <sys/wait.h>   /* Pour wait */
                                                        #include <stdlib.h>     /* Pour fork et malloc */
                                                        
                                                        
                                                        
                                                        void fils(int num_fils, int nb_fils, int *tube){
                                                        
                                                            int tmp=-2;
                                                        
                                                            printf("\nFILS : Je suis le fils n° %d \n", (num_fils+1) );
                                                        
                                                            if( (read( tube[ 2 * nb_fils ] , &tmp, sizeof(int))) == -1 ){
                                                                perror("Erreur read ");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                        
                                                            printf("J'ai recu la valeur %d provenant du père \n", tmp);
                                                        
                                                            /*On ferme l'entrée lecture pour le fils */
                                                            close( tube[ 2*num_fils ]);
                                                        
                                                            exit(EXIT_SUCCESS); 
                                                        }
                                                        
                                                        int main(int argc, char *argv[]){
                                                            int i;
                                                            pid_t pid;
                                                            int statut;
                                                            int tmp = 10;
                                                            int nb_fils;
                                                            int num_fils;
                                                            int *tab_pid=NULL;
                                                            int *tube=NULL;
                                                           
                                                            /* Vérification arguments commande */
                                                            if( argc != 2 ){
                                                                fprintf(stderr, "Usage: %s n\n", argv[0]);
                                                                fprintf(stderr, "\tOu:\n");
                                                                fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                            if( ( atoi(argv[1]) < 1 ) || ( atoi(argv[1]) > 5 ) ){
                                                                fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                        
                                                            /* Recuperation de l'argument nombre de fils */
                                                            nb_fils = atoi(argv[1]);
                                                        
                                                            /* Initialisation nombre tube */
                                                            tube = (int*) malloc( 2 * nb_fils * sizeof(int));
                                                            if( tube == NULL){
                                                                fprintf(stderr, "Erreur malloc tube");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                            for ( i=0 ; i < nb_fils ; i++ ) {
                                                                pipe( &tube[2*i] );
                                                            }
                                                        
                                                            /* Creation d'un tableau de N pid */
                                                            tab_pid = (int*) malloc( nb_fils * sizeof(int));
                                                            if( tab_pid == NULL){
                                                                fprintf(stderr, "Erreur malloc tab_pid");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                        
                                                            /* On ferme les N tubes (entrées lecture) pour le père */
                                                            for( i=0 ; i < nb_fils ; i++){ close( tube[ 2 * i ] ); }
                                                        
                                                            for( i=0 ; i < nb_fils ; i++){
                                                        
                                                                /* Création d'un fils */
                                                                if( (pid = fork()) < 0 ){
                                                                    fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                                                    perror("Erreur : ");
                                                                    exit(EXIT_FAILURE);     
                                                                }
                                                        
                                                                /* on est dans le fils */
                                                                if( pid == 0 ){
                                                        
                                                                    /* On ferme l'entrée ecriture pour le fils */ 
                                                                    close( tube[ (2 * i) + 1 ] );
                                                        
                                                                    fils(i, nb_fils, tube);
                                                                }
                                                        
                                                                /* on est dans le père */
                                                                if( pid > 0) {
                                                                    /* On recupere le pid de chaque fils */
                                                                    tab_pid[i]=pid;            
                                                                }
                                                            } 
                                                        
                                                            /* On attend la création de tous les fils */
                                                            sleep(1);
                                                        
                                                            /*On demande à l'utilisateur le numero du fils*/ 
                                                            printf("\nTapez le numero du fils à selectionner : ");
                                                            scanf("%d",&num_fils);
                                                        
                                                            /* Ecriture dans le tube choisi par l'utilisateur de l'entier "10" (pour test) */
                                                            if( (write( tube[ (2 * (num_fils-1)) + 1 ] , &tmp, sizeof(int))) == -1 ){
                                                                perror("Erreur write ");
                                                                exit(EXIT_FAILURE);
                                                            }
                                                        
                                                            printf("\n Message envoyé au fils %d \n",num_fils);
                                                            
                                                            /* On verifie la fin de chaque fils*/
                                                            for( i=0 ; i < nb_fils ; i++){
                                                        
                                                                if( (waitpid(tab_pid[i] ,&statut, 0)) != tab_pid[i] ) { perror("Erreur lors de l'attente du fils "); exit(EXIT_FAILURE);}
                                                        
                                                                if( WIFEXITED(statut) )
                                                                    printf("PERE : Le fils %d a termine ; valeur retournee = %d ; son PID : %d\n\n", i+1,WEXITSTATUS(statut), tab_pid[i]);
                                                                else
                                                                    printf("Le fils %d a termine anormalement.\n", i+1);
                                                        
                                                            }
                                                        
                                                            /* On ferme les N tubes (entrées ecriture) pour le père */
                                                            for( i=0 ; i < nb_fils ; i++){ close( tube[ (2 * i) + 1 ] ); }
                                                        
                                                            free(tube);
                                                            tube=NULL;
                                                        }
                                                        
                                                        



                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          28 janvier 2021 à 22:59:16

                                                          Ligne 73 tu ferme un bout des tuyaux avant d'avoir créé les processus fils. Qui héritent donc de descripteurs fermés.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            29 janvier 2021 à 10:46:18

                                                            michelbillaud a écrit:

                                                            Ligne 73 tu ferme un bout des tuyaux avant d'avoir créé les processus fils. Qui héritent donc de descripteurs fermés.

                                                            J'ai modifié mon code à partir de tes conseils. J'y suis presque mais je n'ai pas le résultat attendu...

                                                            Mon code, j'ai fermé le bout des tuyaux de lecture pour le père uniquement à chaque création de fils.

                                                            #include <stdio.h>      /* Pour printf, fprintf, perror */
                                                            #include <unistd.h>     /* Pour exit, EXIT_FAILURE, EXIT_SUCCESS et pipe*/
                                                            #include <fcntl.h>
                                                            #include <errno.h>
                                                            #include <sys/types.h>   /* Pour pid_t */
                                                            #include <sys/wait.h>   /* Pour wait */
                                                            #include <stdlib.h>     /* Pour fork et malloc */
                                                            
                                                            
                                                            
                                                            void fils(int num_fils, int nb_fils, int *tube){
                                                            
                                                                int tmp=-2;
                                                            
                                                                printf("\nFILS : fils n° %d créé, son PID est %d\n", (num_fils+1), getpid() );
                                                            
                                                                if( (read( tube[ 2 * nb_fils ] , &tmp, sizeof(int))) == -1 ){
                                                                    perror("Erreur read ");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                            
                                                                printf("Je suis fils n° %d. J'ai recu la valeur %d provenant du père \n", (num_fils+1), tmp);
                                                            
                                                                /*On ferme l'entrée lecture pour le fils */
                                                                close( tube[ 2*num_fils ]);
                                                            
                                                                exit(EXIT_SUCCESS); 
                                                            }
                                                            
                                                            int main(int argc, char *argv[]){
                                                                int i;
                                                                pid_t pid;
                                                                int statut;
                                                                int tmp = 10;
                                                                int nb_fils;
                                                                int num_fils;
                                                                int *tab_pid=NULL;
                                                                int *tube=NULL;
                                                               
                                                                /* Vérification arguments commande */
                                                                if( argc != 2 ){
                                                                    fprintf(stderr, "Usage: %s n\n", argv[0]);
                                                                    fprintf(stderr, "\tOu:\n");
                                                                    fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                                if( ( atoi(argv[1]) < 1 ) || ( atoi(argv[1]) > 5 ) ){
                                                                    fprintf(stderr, "\t\t n : nombre de processus fils à créer entre 1 et 5\n");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                            
                                                                /* Recuperation de l'argument nombre de fils */
                                                                nb_fils = atoi(argv[1]);
                                                            
                                                                /* Initialisation nombre tube */
                                                                tube = (int*) malloc( 2 * nb_fils * sizeof(int));
                                                                if( tube == NULL){
                                                                    fprintf(stderr, "Erreur malloc tube");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                                for ( i=0 ; i < nb_fils ; i++ ) {
                                                                    pipe( &tube[2*i] );
                                                                }
                                                            
                                                                /* Creation d'un tableau de N pid */
                                                                tab_pid = (int*) malloc( nb_fils * sizeof(int));
                                                                if( tab_pid == NULL){
                                                                    fprintf(stderr, "Erreur malloc tab_pid");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                            
                                                                for( i=0 ; i < nb_fils ; i++){
                                                            
                                                                    /* Création d'un fils */
                                                                    if( (pid = fork()) < 0 ){
                                                                        fprintf(stderr, "Erreur lors de la création du fils %d\n", i );
                                                                        perror("Erreur : ");
                                                                        exit(EXIT_FAILURE);     
                                                                    }
                                                            
                                                                    /* on est dans le fils */
                                                                    if( pid == 0 ){
                                                            
                                                                        /* On ferme l'entrée ecriture pour le fils */ 
                                                                        close( tube[ (2 * i) + 1 ] );
                                                            
                                                                        fils(i, nb_fils, tube);
                                                                    }
                                                            
                                                                    /* on est dans le père */
                                                                    if( pid > 0) {
                                                                        /* On ferme les N tubes (entrées lecture) pour le père */
                                                                         //close( tube[ 2 * i ] );
                                                            
                                                                        /* On recupere le pid de chaque fils */
                                                                        tab_pid[i]=pid;            
                                                                    }
                                                                } 
                                                            
                                                                /* On attend la création de tous les fils */
                                                                sleep(1);
                                                            
                                                                /*On demande à l'utilisateur le numero du fils*/ 
                                                                printf("\nTapez le numero du fils à selectionner : ");
                                                                scanf("%d",&num_fils);
                                                            
                                                                /* Ecriture dans le tube choisi par l'utilisateur de l'entier "10" (pour test) */
                                                                if( (write( tube[ (2 * (num_fils-1)) + 1 ] , &tmp, sizeof(int))) == -1 ){
                                                                    perror("Erreur write ");
                                                                    exit(EXIT_FAILURE);
                                                                }
                                                            
                                                                printf("\nMessage envoyé au fils n°%d \n",num_fils);
                                                                
                                                                /* On verifie la fin de chaque fils*/
                                                                for( i=0 ; i < nb_fils ; i++){
                                                            
                                                                    if( (waitpid(tab_pid[i] ,&statut, 0)) != tab_pid[i] ) { perror("Erreur lors de l'attente du fils "); exit(EXIT_FAILURE);}
                                                            
                                                                    if( WIFEXITED(statut) )
                                                                        printf("PERE : Le fils %d a termine ; valeur retournee = %d ; son PID : %d\n\n", i+1,WEXITSTATUS(statut), tab_pid[i]);
                                                                    else
                                                                        printf("Le fils %d a termine anormalement.\n", i+1);
                                                            
                                                                }
                                                            
                                                                /* On ferme les N tubes (entrées ecriture) pour le père */
                                                                for( i=0 ; i < nb_fils ; i++){ close( tube[ (2 * i) + 1 ] ); }
                                                            
                                                                free(tube);
                                                                tube=NULL;
                                                            }
                                                            
                                                            



                                                            -
                                                            Edité par NATHdb 29 janvier 2021 à 11:43:50

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              29 janvier 2021 à 12:38:05

                                                              Un problème avec un numéro de descripteur incorrect ?

                                                              Look

                                                              void fils(int num_fils, int nb_fils, int *tube){
                                                              
                                                                 read( tube[ 2 * nb_fils ] , ..., ....);


                                                              > J'ai modifié mon code à partir de tes conseils.

                                                              Dans le genre "et c'est donc à cause de tes conseils à la noix que ça ne marche pas" :-)

                                                              hum,  en tout cas pas celui-là :

                                                              Il ne faut passer à la fonction "fils" 
                                                              que les informations qui lui sont absolument nécessaires.
                                                              
                                                              Ca évitera les accidents comme celui-ci
                                                              [...]


                                                              Les accidents se reproduisent, pour les mêmes raisons.  Le processus fils a besoin de SON numéro, et d'UN (seulement un, ONLY ONE, NUR EINS) descripteur.

                                                              -
                                                              Edité par michelbillaud 29 janvier 2021 à 12:44:42

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              Discussion Pere vers Fils : Processus

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown