Partage
  • Partager sur Facebook
  • Partager sur Twitter

communication interprocess

    7 novembre 2022 à 6:44:18

    Bonjour je vois bien qu'un fils peut communiquer avec le père via tube mais est ce que deux fils peuvent communiquer entre eux via tube ? un truc comme ça

    fils1--->fils2--->fils3---->pére---->fils1  

    • Partager sur Facebook
    • Partager sur Twitter
      7 novembre 2022 à 10:48:25

      amstaTargaryen a écrit:

      Bonjour je vois bien qu'un fils peut communiquer avec le père via tube mais

      1) est ce que deux fils peuvent communiquer entre eux via tube ?

      2) un truc comme ça

      fils1--->fils2--->fils3---->pére---->fils1  


      1) oui, sans problème.

      • le père crée le tube
      • il "forke" deux fils, qui en héritent
      • les fils peuvent communiquer (pendant ce temps, le père peut fermer le tube dont il n'a pas l'usage)
      Pour essayer : écrire un programme minimum dans lequel
      • le père crée un tube
      • il lance un fils qui fait quelques tours de boucle avec attente quelques secondes,  envoi d'un message "hello" dans le tube, puis s'arrête.
      • il lance un autre fils qui affiche les messages qu'il reçoit, jusqu'à fin des données.
      • et il attend que les fils aient terminé.
       Conseil : ne pas oublier de fermer les bouts de tubes dont on ne se sert pas.
      (solution plus tard, quand vous aurez avancé)


      2) Comprends pas le schéma. Il y a un tube qui passe à travers des processus ? Ou c'est autant de tubes ?

      -
      Edité par michelbillaud 7 novembre 2022 à 19:12:15

      • Partager sur Facebook
      • Partager sur Twitter
        7 novembre 2022 à 19:35:31

        michelbillaud a écrit:

        amstaTargaryen a écrit:

        Bonjour je vois bien qu'un fils peut communiquer avec le père via tube mais

        1) est ce que deux fils peuvent communiquer entre eux via tube ?

        2) un truc comme ça

        fils1--->fils2--->fils3---->pére---->fils1  

        1) oui, sans problème.

        • le père crée le tube
        • il "forke" deux fils, qui en héritent
        • les fils peuvent communiquer (pendant ce temps, le père peut fermer le tube dont il n'a pas l'usage)
        Pour essayer : écrire un programme minimum dans lequel
        • le père crée un tube
        • il lance un fils qui fait quelques tours de boucle avec attente quelques secondes,  envoi d'un message "hello" dans le tube, puis s'arrête.
        • il lance un autre fils qui affiche les messages qu'il reçoit, jusqu'à fin des données.
        • et il attend que les fils aient terminé.
         Conseil : ne pas oublier de fermer les bouts de tubes dont on ne se sert pas.
        (solution plus tard, quand vous aurez avancé)


        2) Comprends pas le schéma. Il y a un tube qui passe à travers des processus ? Ou c'est autant de tubes ?

        -
        Edité par michelbillaud il y a 16 minutes

        bonsoir, oui enfaite le schéma c'est bien 4 tubes différents le but c'est  que le fils 1 envoie un message qui va être modifié à la traversé de chaque fils via les tubes afin d'arriver au père  

        -
        Edité par amstaTargaryen 7 novembre 2022 à 19:36:15

        • Partager sur Facebook
        • Partager sur Twitter
          7 novembre 2022 à 23:37:12

          amstaTargaryen a écrit:

          bonsoir, oui enfaite le schéma c'est bien 4 tubes différents le but c'est  que le fils 1 envoie un message qui va être modifié à la traversé de chaque fils via les tubes afin d'arriver au père  

          Bref, le problème de fond, c'est de faire communiquer 2 processus par un tube dont ils ont hérité.

          • Partager sur Facebook
          • Partager sur Twitter
            8 novembre 2022 à 1:43:28

            En m'inspirant de ceci:

            http://www.zeitoun.net/articles/communication-par-tuyau/start

            J'ai écrit le code suivant pour illustrer le principe avec pipe (_pipe sur Windows):
            Ici, le fils 0 représente le père. Pour boucler sur N fils, il faut N+1 pipe.

            Chaque fils recevra deux pipe, celui avec son prédécesseur et celui avec son successeur.

            -
            #include <stdio.h>
            #include <windows.h>
            #include <fcntl.h>
            #define np 4
            int main(void) {
                int pipes[np][2];   // np pipes.
                for(int p = 0; p < np; p++) {
                    _pipe(pipes[p], 1024, _O_TEXT);
                    printf("pipe %d, fils %d vers fils %d, input=%d,  output=%d\n", p, p, (p+1)%np, pipes[p][0], pipes[p][1]);
                }
               // Procédure de transfert:
                for(int p = 0; p < np; p++) {
                    printf("Le fils %d lira sur %d et écrira sur %d\n", p, pipes[(p-1+np)%np][0], pipes[p][1]);
                }
                return 0;
            }
            -
            pipe 0, fils 0 vers fils 1, input=3,  output=4                                                                          
            pipe 1, fils 1 vers fils 2, input=5,  output=6                                                                          
            pipe 2, fils 2 vers fils 3, input=7,  output=8                                                                          
            pipe 3, fils 3 vers fils 0, input=9,  output=10                                                                         
            Le fils 0 lira sur 9 et écrira sur 4                                                                                    
            Le fils 1 lira sur 3 et écrira sur 6                                                                                    
            Le fils 2 lira sur 5 et écrira sur 8                                                                                    
            Le fils 3 lira sur 7 et écrira sur 10

            -
            Edité par PierrotLeFou 8 novembre 2022 à 5:06:43

            • Partager sur Facebook
            • Partager sur Twitter

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

              9 novembre 2022 à 10:28:30

              Bon alors voila un exemple de partage de tuyau par deux processus fils, un écrivain qui y met des messages, un fils qui lit ce qu'il y trouve.

              Attention, Seuls Ceux Qui Ont Un QI de 160 Vont Voir Qu'il Y A Un Problème

              #include <stdio.h>
              #include <stdlib.h>
              #include <stdbool.h>
              #include <unistd.h> 
              #include <sys/types.h>
              #include <sys/wait.h>
              
              void ecrire_dans(int out) 
              {
              	for (int i = 1; i <= 5; i++) {
              		sleep(1);
              		char message[100];
              		size_t len = sprintf(message, "Envoi numéro %d", i);
              		printf("Ecrivain %d> envoi de \"%s\"\n", i, message);
              		write(out, message, len);     
              	}
              }
              
              void lire_sur(int in)
              {
              	char message[100 + 1];
              	int nb_received = 0;
              	while (true) {
              		size_t len = read(in, message, 100);
              		if (len <= 0) break;
              
              		nb_received ++;
              		message[len] = '\0';
              		printf("Lecteur %d > réception de \"%s\"\n", nb_received, message);
              		// sleep(2);             // fait dérailler le programme.
              	}
              	printf("Lecteur> fin des données\n");
              }
              
              int main()
              {
              	printf("DEBUT\n");
              	int tube[2];
              	pipe(tube);
              	
              	printf("Main > lancement écrivain\n");
              	pid_t ecrivain = fork();
              	if (ecrivain == 0) {
              		close(tube[0]);
              		ecrire_dans(tube[1]);
              		exit(0);
              	}
              	close(tube[1]); // le père et le lecteur n'en ont pas besoin
              
              	printf("Main > lancement lecteur\n");
              	pid_t lecteur = fork();
              	if (lecteur == 0) {
              		lire_sur(tube[0]);
              		exit(0);
              	}
              	close(tube[0]); // le père n'en a pas besoin
              
              	printf("Main> en attente\n");
              	wait(NULL);
              	printf("Main> Un des processus fils s'est arrếté\n");
              	wait(NULL);
              	printf("Main> L'autre processus fils s'est arrêté\n");
              	printf("FIN\n");
              
              	return EXIT_SUCCESS;
              }
              

              Quand ça s'exécute, ça fait



              cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
              ./prog
              DEBUT
              Main > lancement écrivain
              Main > lancement lecteur
              Main> en attente
              Ecrivain 1> envoi de "Envoi numéro 1"
              Lecteur 1 > réception de "Envoi numéro 1"
              Ecrivain 2> envoi de "Envoi numéro 2"
              Lecteur 2 > réception de "Envoi numéro 2"
              Ecrivain 3> envoi de "Envoi numéro 3"
              Lecteur 3 > réception de "Envoi numéro 3"
              Ecrivain 4> envoi de "Envoi numéro 4"
              Lecteur 4 > réception de "Envoi numéro 4"
              Ecrivain 5> envoi de "Envoi numéro 5"
              Lecteur 5 > réception de "Envoi numéro 5"
              Lecteur> fin des données
              Main> Un des processus fils s'est arrêté
              Main> L'autre processus fils s'est arrêté
              FIN

              Par contre, ça repose sur le fait que le 'lecteur" a le temps de consommer les messages un par un, à cause de la temporisation dans l'écrivain.

              Si on décommente la ligne

              sleep(2);             // fait dérailler le programme.

              C'est plus pareil

              cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
              ./prog
              DEBUT
              Main > lancement écrivain
              Main > lancement lecteur
              Main> en attente
              Ecrivain 1> envoi de "Envoi numéro 1"
              Lecteur 1 > réception de "Envoi numéro 1"
              Ecrivain 2> envoi de "Envoi numéro 2"
              Lecteur 2 > réception de "Envoi numéro 2"
              Ecrivain 3> envoi de "Envoi numéro 3"
              Ecrivain 4> envoi de "Envoi numéro 4"
              Lecteur 3 > réception de "Envoi numéro 3Envoi numéro 4"   // OOPS !
              Ecrivain 5> envoi de "Envoi numéro 5"
              Main> Un des processus fils s'est arrêté
              Lecteur 4 > réception de "Envoi numéro 5"
              Lecteur> fin des données
              Main> L'autre processus fils s'est arrêté
              FIN
              
              

              ça peut se désynchroniser. En effet l'écrivain a eu le temps d'envoyer 2 messages avant que le lecteur (qui fait des pauses) se remette à lire.

              Donc les 2 messages 3 et 4 se sont accumulés dans le tuyau, et le lecteur les a lus en bloc, comme si c'était un seul.

              (Il pourrait arriver aussi - avec d'autres valeurs de délai - que les messages s'accumulent au point de remplir le pipe. Du coup, l'écrivain sera bloqué.)


              Conclusion : ceci est une démo de partage de tuyau par deux processus fils, mais pas un modèle à suivre bêtement. Si on veut une synchro entre lecteur et écrivain pour travailler message par message, il ne faut pas s'y prendre comme ça.

              -
              Edité par michelbillaud 9 novembre 2022 à 12:47:48

              • Partager sur Facebook
              • Partager sur Twitter
                10 novembre 2022 à 2:02:09

                Comme je n'ai qu'un QI de 40 avec 3 ou 4 neurones ... j'ai fait le test suivant:
                sprintf ne compte pas le '\0' de fin de chaîne.
                On peut bloquer l'écrivain (sleep) ou avoir un code de fin de message que le lecteur devrait savoir interpréter.
                Dans certains protocoles, l'écrivain envoie le nombre d'octets à transmettre au début du message.
                -
                #include <stdio.h>
                int main(){
                    char msg[100] = { "************************" };
                    size_t l = sprintf(msg, "Number %d", 4);
                    printf("%d, %s", l, msg);
                }
                -
                8, Number 4
                • Partager sur Facebook
                • Partager sur Twitter

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

                  10 novembre 2022 à 6:51:41

                  On peut s'y prendre comme ça. Le but de ma remarque, c'était de souligner qu'un pipe c'était un flux d'octets et non une séquence de messages.  Même si il y a quelques propriétés qui laissent éventuellement croire le contraire :

                  • L'écriture par write dans un tuyau est atomique : soit il y reste assez de place pour y mettre tout  qui ce qu'on indique par drive, soit l'écrivain est bloqué en attendant. 
                  • Côté lecteur, il est possible de lire ce qui est présent dans le pipe, même si c'est une taille inférieure au tampon indiqué par read, et que la fin n'est pas atteinte (contrairement aux fichiers)

                  C'est ce qui fait marcher l'exemple. Par miracle. Parce que la temporisation fait qu'on est PRESQUE sûrs qu'il n'y a jamais qu'un message à la fois dans le tuyau.

                  La solution la plus simple si on veut transmettre proprement (sans compter sur des temporisations) des messages plutôt qu'un flux : messages de même taille.

                  Sinon, présence dans chaque message d'une entête (de taille fixe) indiquant la taille des données qui suivent.  Écriture en un seul write (en tête + donnees) pour être sûr que les données sont dans le pipe juste après que le lecteur a lu l'entête....

                  Illustration, ce coup-ci avec 3 processus fils qui envoient chacun 5 messages, avec des temporisations aléatoires. Temporisation aussi du côté du lecteur.

                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <stdbool.h>
                  #include <unistd.h>
                  #include <sys/types.h>
                  #include <sys/wait.h>
                  #include <stddef.h>
                  
                  struct Entete {
                      ssize_t longueur_donnees;
                  };
                  
                  struct Message {
                      struct Entete entete;
                      char donnees[100];
                  };
                  
                  void ecrire_dans(int id_ecrivain, int out)
                  {
                      srand(id_ecrivain);
                      for (int num_message = 1; num_message <= 5; num_message++) {
                          sleep(rand() % 4);
                          struct Message message;
                          size_t nb_chars = sprintf(message.donnees,
                                                    "message numéro %d envoyé par écrivain %d",
                                                    num_message, id_ecrivain);
                          message.entete.longueur_donnees = nb_chars;
                  
                          printf("Ecrivains> \"%s\"\n", message.donnees);
                          write(out, & message, offsetof(struct Message, donnees) + nb_chars);
                      }
                  }
                  
                  void lire_sur(int in)
                  {
                      struct Entete entete;
                      char donnees[100 + 1];
                      int nb_received = 0;
                      while (true) {
                          // lecture entete si possible, sinon fin
                          if (read(in, & entete, sizeof(entete)) <= 0) break;
                          // lecture données
                          read(in, donnees, entete.longueur_donnees);
                          nb_received ++;
                          donnees[entete.longueur_donnees] = '\0';   
                          printf("Lecteur %d > réception de \"%s\"\n", nb_received, donnees);
                          sleep(rand() % 3);
                      }
                      printf("Lecteur> fin des données\n");
                  }
                  
                  int main()
                  {
                      const int nb_ecrivains = 3;
                      printf("DEBUT\n");
                      int tube[2];
                      pipe(tube);
                  
                      for (int id = 1; id <= nb_ecrivains; id++) {
                          printf("Main > lancement écrivain %d\n", id);
                          pid_t ecrivain = fork();
                          if (ecrivain == 0) {
                              close(tube[0]);
                              ecrire_dans(id, tube[1]);
                              exit(0);
                          }
                      }
                  
                      close(tube[1]); // le père et le lecteur n'en ont pas besoin
                  
                      printf("Main > lancement lecteur\n");
                      pid_t lecteur = fork();
                      if (lecteur == 0) {
                          lire_sur(tube[0]);
                          exit(0);
                      }
                      close(tube[0]); // le père n'en a pas besoin
                  
                      printf("Main> en attente\n");
                      wait(NULL);
                      for (int i = 1; i <= nb_ecrivains + 1; i++) {  // lecteur + ecrivains
                          printf("Main> Arret processus fils %i/%i\n", i, nb_ecrivains+1);
                          wait(NULL);
                      }
                      printf("FIN\n");
                  
                      return EXIT_SUCCESS;
                  }
                  

                  Trace d'une exécution

                  $ cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
                  
                  $ ./prog
                  DEBUT
                  Main > lancement écrivain 1
                  Main > lancement écrivain 2
                  Main > lancement écrivain 3
                  Main > lancement lecteur
                  Main> en attente
                  Ecrivains> "message numéro 1 envoyé par écrivain 2"
                  Ecrivains> "message numéro 1 envoyé par écrivain 3"
                  Lecteur 1 > réception de "message numéro 1 envoyé par écrivain 2"
                  Ecrivains> "message numéro 1 envoyé par écrivain 1"
                  Ecrivains> "message numéro 2 envoyé par écrivain 3"
                  Lecteur 2 > réception de "message numéro 1 envoyé par écrivain 3"
                  Ecrivains> "message numéro 3 envoyé par écrivain 3"
                  Ecrivains> "message numéro 4 envoyé par écrivain 3"
                  Lecteur 3 > réception de "message numéro 1 envoyé par écrivain 1"
                  Lecteur 4 > réception de "message numéro 2 envoyé par écrivain 3"
                  Ecrivains> "message numéro 5 envoyé par écrivain 3"
                  Main> Arret processus fils 1/4
                  Ecrivains> "message numéro 2 envoyé par écrivain 2"
                  Ecrivains> "message numéro 2 envoyé par écrivain 1"
                  Ecrivains> "message numéro 3 envoyé par écrivain 2"
                  Lecteur 5 > réception de "message numéro 3 envoyé par écrivain 3"
                  Ecrivains> "message numéro 3 envoyé par écrivain 1"
                  Lecteur 6 > réception de "message numéro 4 envoyé par écrivain 3"
                  Ecrivains> "message numéro 4 envoyé par écrivain 2"
                  Lecteur 7 > réception de "message numéro 5 envoyé par écrivain 3"
                  Ecrivains> "message numéro 4 envoyé par écrivain 1"
                  Ecrivains> "message numéro 5 envoyé par écrivain 2"
                  Main> Arret processus fils 2/4
                  Lecteur 8 > réception de "message numéro 2 envoyé par écrivain 2"
                  Lecteur 9 > réception de "message numéro 2 envoyé par écrivain 1"
                  Lecteur 10 > réception de "message numéro 3 envoyé par écrivain 2"
                  Ecrivains> "message numéro 5 envoyé par écrivain 1"
                  Main> Arret processus fils 3/4
                  Lecteur 11 > réception de "message numéro 3 envoyé par écrivain 1"
                  Lecteur 12 > réception de "message numéro 4 envoyé par écrivain 2"
                  Lecteur 13 > réception de "message numéro 4 envoyé par écrivain 1"
                  Lecteur 14 > réception de "message numéro 5 envoyé par écrivain 2"
                  Lecteur 15 > réception de "message numéro 5 envoyé par écrivain 1"
                  Lecteur> fin des données
                  Main> Arret processus fils 4/4
                  FIN

                  On en a bien reçu 15 = 3 * 5 : bingo.



                  -
                  Edité par michelbillaud 10 novembre 2022 à 9:46:17

                  • Partager sur Facebook
                  • Partager sur Twitter

                  communication interprocess

                  × 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