IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Sémaphore : "sem_op = 0" n'arrive pas à faire attendre le processus père.


Sujet :

C

  1. #1
    Membre actif
    Homme Profil pro
    Dév Java/JavaEE
    Inscrit en
    Décembre 2012
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dév Java/JavaEE

    Informations forums :
    Inscription : Décembre 2012
    Messages : 53
    Points : 203
    Points
    203
    Par défaut Sémaphore : "sem_op = 0" n'arrive pas à faire attendre le processus père.
    Bonjour,

    Dans un travail que j'ai à faire, sous Linux, j'utilise deux programmes, un client et un serveur.
    Mon souci actuel est dans le serveur :
    Le processus père fait un fork() pour créer un fils.
    Dans le fils, je dois écrire deux messages au père via un tube anonyme.
    Le père doit alors lire ces deux messages, toujours via le tube anonyme.

    Le problème est que le père lit en premier dans le tube anonyme.
    Sa lecture anticipée est donc une erreur.

    J'ai alors cherché à implémenter un ensemble de sémaphore, définit en tant que mutex, juste avant de faire appel à la primitive fork().
    Puis, dans le père, je cherche à faire attendre le père via ce mutex définit par un sem_op = 0.
    Le problème est que le père n'attend toujours pas le fils.

    Voici mon programme serveur, dans les grandes lignes :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
     
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <sys/sem.h>
     
    main()
    {
      /* Initialisation des variables. */
      ...
      int pid;
      int tube[2];
      struct sembuf operation;
      char chaine1[1], chaine2[2];
      ...
     
      while (1)
      {
          ...
     
          /* Création d'un ensemble de sémaphores. */
          semid = semget( (key_t)999, 1, IPC_CREAT | IPC_EXCL | 0660 );
          /* Initialisation d'un Mutex. */
          semctl( semid, 0, SETVAL, 1);
     
          ...
     
          pid = fork();
          if(pid == -1){ perror("fork");  exit(1); }
     
          else if(pid == 0) /* Le fils. */
          {      
     
          	  /* Réquisition du Mutex. */
          	  operation.sem_num = 0;
          	  operation.sem_op = -1;
          	  operation.sem_flg = 0;
     
              semop (semid, &operation, 1);
          	  ...
     
          	  /* Libération du Mutex. */      		
          	  operation.sem_num = 0;
          	  operation.sem_op = 1;
          	  operation.sem_flg = 0;
     
              semop (semid, &operation, 1);
     
          	  /* Le père tuera le mutex. */
     
    	  /* tube anonyme créé par le fils. */
    	  pipe(tube);
    	  /* Le fils écrit au père. */
    	  close(tube[0]);
     
    	  write(tube[1], "A", 1); 
    	  write(tube[1], "BC", 2);
     
    	  close(tube[1]);
     
    	   exit(0);
          }
          else /* Le père. */
          {
     
     
             printf("\nLe pere.\n");
     
             /* Attente de l'écriture du fils par le père, contrôlée par la Mutex. */      		
             operation.sem_num = 0;
             operation.sem_op = 0;
             operation.sem_flg = 0;
     
             semop (semid, &operation, 1);
     
             close(tube[1]);
     
             /* Le père lit le fils. */
     
             read(tube[0], chaine1, 1);
             printf("%s\n", chaine1);
     
            read(tube[0], chaine2, 2);
            printf("%s\n", chaine2);
     
            close(tube[0]);
     
            wait();/* Le père attend la fin du fils, de plus, le tube anonyme fils-père est définitivement détruit. */					
     
            /* Destruction du Mutex créé par le fils. */
        	semctl( semid, 0, IPC_RMID, 0);
     
          }//fin du père
     
      }//fin du while
     
      exit(0);
    }
    Où est donc le problème ?
    Comment faire ?

    Je précise débuter avec les IPC de Linux et n'avoir jamais réussi à faire attendre un processus avec cette technique du sem_op = 0 dans un autre programme.

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 673
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 673
    Points : 30 962
    Points
    30 962
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par siro75 Voir le message
    Le problème est que le père lit en premier dans le tube anonyme.
    Sa lecture anticipée est donc une erreur.
    Salut
    Normalement non. Lire un tube mémoire alors qu'il n'y a rien d'écrit bloque le lecteur jusqu'à ce qu'il y ait un processus qui y écrive. C'est justement le but d'un pipe: un moyen de communication synchrone dont la synchronisation est gérée par le noyau. C'est dommage de programmer de ton coté une synchro "en plus"...

    Toutefois si tu veux être certain que le fils commence en premier, rajoute un petit sleep(1) au début du père. C'est pas super propre mais pour un premier test ça peut t'aider...

    Citation Envoyé par siro75 Voir le message
    J'ai alors cherché à implémenter un ensemble de sémaphore, définit en tant que mutex, juste avant de faire appel à la primitive fork().
    Puis, dans le père, je cherche à faire attendre le fils via ce mutex définit par un sem_op = 0.
    A condition alors que ton fils l'ait mis à 1 pour le faire décroitre et non l'inverse...

    Citation Envoyé par siro75 Voir le message
    Voici mon programme serveur, dans les grandes lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <sys/sem.h>
    
    main()
    {
      /* Initialisation des variables. */
      ...
      int pid;
      int tube[2];
      struct sembuf operation;
      char chaine1[1   /* Un tableau pour un seul élément ??? */], chaine2[2];
      ...
      
      while (1)
      {
          ...
          
          /* Création d'un ensemble de sémaphores. */
          semid = semget( (key_t)999, 1, IPC_CREAT | IPC_EXCL | 0660 );
          /* 
                Concernant la clef, t'as le droit d'utiliser la macro 
                IPC_PRIVATE qui te garantit l'unicité de ton ipc
                Inutile si l'ipc doit être accessible par 2 programmes distincts
                mais utile dans le cas d'une communication père-fils...
          */
          /* Initialisation d'un Mutex. */
          semctl( semid, 0, SETVAL, 1);
    
          ...
    
          pid = fork();
          if(pid == -1){ perror("fork");  exit(1); }
    
          else if(pid == 0) /* Le fils. */
          {      
          		
          	  /* Réquisition du Mutex. */
          	  operation.sem_num = 0;
          	  operation.sem_op = -1;
          	  operation.sem_flg = 0;
              semop (semid, &operation, 1);
              /*
                    Me semble que si tu veux être sûr que le père attende l'écriture du fils, 
                    tu ne dois faire descendre le sémaphore à 0 que quand 
                    le fils est prêt, c'est à dire qu'il a déjà écrit...
              */
    
    
          	  ...
          		
          	  /* Libération du Mutex. */      		
          	  operation.sem_num = 0;
          	  operation.sem_op = 1;
          	  operation.sem_flg = 0;
              semop (semid, &operation, 1);
          		
          	  /* Le père tuera le mutex. */
          	      			
    	  /* tube anonyme créé par le fils. */
    	  pipe(tube);
    	  /* Le fils écrit au père. */
    	  close(tube[0]);
    	  write(tube[1], "A", 1); 
    	  write(tube[1], "BC", 2);
    
              // Attention tu n'as pas écrit le '\0'...
    
    	  close(tube[1]);
    			
    	   exit(0);
          }
          else /* Le père. */
          {
    			
    	
             printf("\nLe pere.\n");
    			
             /* Attente de l'écriture du fils par le père, contrôlée par la Mutex. */      		
             operation.sem_num = 0;
             operation.sem_op = 0;
             operation.sem_flg = 0;
    
             semop (semid, &operation, 1);
          
             close(tube[1]);
    
             /* Le père lit le fils. */
    			
             read(tube[0], chaine1, 1);
             printf("%s\n", chaine1);
             
            read(tube[0], chaine2, 2);
            printf("%s\n", chaine2);
            /* Attention, le fils a écrit {'A'} puis {'A', 'B'}. Nulle part il n'a écrit le '\0'. Donc tes chaines 1 et 2 n'en sont pas => crash probable ... */
    			
            close(tube[0]);
            
            wait();/* Le père attend la fin du fils, de plus, le tube anonyme fils-père est définitivement détruit. */					
    			
            /* Destruction du Mutex créé par le fils. */
        	semctl( semid, 0, IPC_RMID, 0);
    
          }//fin du père
        	
      }//fin du while
      
      exit(0);
    }
    Où est donc le problème ?
    Comment faire ?
    Voir mes commentaires en rouge dans ton code... mais comme je te l'ai dit, un sémaphore est inutile ici...

    Citation Envoyé par siro75 Voir le message
    Je précise débuter avec les IPC de Linux et n'avoir jamais réussi à faire attendre un processus avec cette technique du sem_op = 0 dans un autre programme.
    Si t'as un pb avec un appel système alors errno et strerror() sont là pour t'aider. Cependant je pense que peut-être tu n'as pas bien compris le principe d'un sem_op=0.
    Un sem_op=0 attend que le sémaphore passe à 0. C'est à dire qu'un processus P1 le met à 1 puis un processus P2 demande un sem_op=0 (avec éventuellement un processus P3 et P4 et etc...).
    Quand tout le monde est prêt, alors P1 passe le sémaphore à 0 et tous les P2 P3 P4 qui attendaient cet évènement sont alors libérés et peuvent démarrer. C'est en fait le principe d'un départ groupé.

    D'un autre coté, imagine que tu demandes à P2 d'attendre P1 avec un sem_op=0 mais que P1 ait travaillé si vite qu'il ait déjà mis le sémaphore à 0 avant que P2 ne commence, tu auras alors l'impression que ton code ne fonctionne pas alors qu'en fait il fonctionne mais l'attente a été shuntée...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre actif
    Homme Profil pro
    Dév Java/JavaEE
    Inscrit en
    Décembre 2012
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dév Java/JavaEE

    Informations forums :
    Inscription : Décembre 2012
    Messages : 53
    Points : 203
    Points
    203
    Par défaut
    Je vais tester l'idée du sleep(1); à laquelle j'avais pensé mais ça me semblait du bricolage alors je ne l'ai même pas testée mais me suis plutôt acharné sur diverses implémentations de la méthode semop().
    Je confirmerai ou infirmerai par la suite.

    Merci pour les remarques en rouge et surtout l'explication de la macro IPC_PRIVATE.


    Sinon, c'est bizarre mais votre deuxième citation ne correspond pas à mon texte initial :

    Dans votre message,il y a :

    je cherche à faire attendre le fils
    Le mien du départ :

    je cherche à faire attendre le père

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 673
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 673
    Points : 30 962
    Points
    30 962
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par siro75 Voir le message
    Sinon, c'est bizarre mais votre deuxième citation ne correspond pas à mon texte initial :
    Citation Envoyé par siro75 Voir le message
    dans le père, je cherche à faire attendre le père
    Oui, j'ai modifié la citation car je croyais une erreur et je comprenais "le père attend le père" alors que concrètement, le père attend le fils.
    Mais après une seconde lecture, on peut effectivement aussi comprendre "dans le père, je cherche à lui faire attendre..."

    Concernant le sleep(1) c'est effectivement du bricolage. Donc tout dépend du but de ce truc. Pour un simple TP ou démo de pipe() ça peut le faire.
    Maintenant si ton programme doit contrôler la température d'une cuve d'une centrale nucléaire et communiquer avec les autres programmes c'est peut-être un peu plus moyen...

    De toute façon dans l'absolu celui qui commence tu t'en moques. Si c'est le fils alors il écrira et ensuite le père lira ce qui a été écrit... et si c'est le père alors il tentera de lire mais comme rien n'a été écrit il restera bloqué jusqu'à ce que le fils ait écrit...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre actif
    Homme Profil pro
    Dév Java/JavaEE
    Inscrit en
    Décembre 2012
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dév Java/JavaEE

    Informations forums :
    Inscription : Décembre 2012
    Messages : 53
    Points : 203
    Points
    203
    Par défaut
    Pour information, j'ai réussi à trouver sur Internet une implémentation de mémoire partagée (concernant une structure) qui marche très bien et grâce à cela, j'ai pu m'en insipirer pour faire une mémoire partagée sur un tableau de structures dont j'avais en fait besoin :
    Voir page 12 de ce document :
    http://laurent.bobelin.free.fr/docum.../C6handout.pdf

    Ainsi, je n'ai plus du tout à utiliser le code dont je parlais plus haut. J'avais dû faire ce code car mon implémentation de mémoire partagée relative à un tableau de structures ne fonctionnait pas. Je ne maîtrisais pas trop les mémoires partagées à ce moment-là. Maintenant ça va beaucoup mieux !

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 673
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 673
    Points : 30 962
    Points
    30 962
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par siro75 Voir le message
    Ainsi, je n'ai plus du tout à utiliser le code dont je parlais plus haut. J'avais dû faire ce code car mon implémentation de mémoire partagée relative à un tableau de structures ne fonctionnait pas. Je ne maîtrisais pas trop les mémoires partagées à ce moment-là. Maintenant ça va beaucoup mieux !
    Ce ne sont pas les mêmes outils et donc ils n'ont pas les mêmes buts
    Le pipe sert à faire une communication synchrone. Deux processus communiquant l'un l'autre. La synchronisation est assurée par le noyau
    Les IPC servent à faire de la communication asynchrone. Un processus P1 écrivant ses infos puis pouvant disparaitre tandis que les infos sont conservées (par le noyau). Ensuite un processus P2 pouvant venir récupérer les infos.
    Les IPC de comm se subdivisent en files de message (msq) qui sont comme des télésièges (des messages en enfilade où on récupère à chaque fois le premier) et la mémoire partagée (shm) qui est une grande zone ou on met en vrac ce que l'on veut où on veut. Ce qui nécessite le plus souvent la mise en place de sémaphores (sem) si on veut protéger la shm des accès concurrents

    Donc si la comm est temporaire (les infos lues ne sont plus utiles) et que les processus restent actif durant la comm, le pipe est plus indiqué. Si les processus ne restent pas actifs alors c'est la msq. Maintenant si les datas de travail doivent rester dispos (par exemple style MMORPG) alors la shm est plus indiquée...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Membre actif
    Homme Profil pro
    Dév Java/JavaEE
    Inscrit en
    Décembre 2012
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dév Java/JavaEE

    Informations forums :
    Inscription : Décembre 2012
    Messages : 53
    Points : 203
    Points
    203
    Par défaut
    Précisions toujours bonnes à rappeler.
    Merci.

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

Discussions similaires

  1. Une requête que je n'arrive pas à faire
    Par Denti-fritz dans le forum Langage SQL
    Réponses: 3
    Dernier message: 07/12/2005, 13h53
  2. Très débutant : je n'arrive pas à faire fonctionner le JDK
    Par miltonis dans le forum Général Java
    Réponses: 20
    Dernier message: 19/10/2005, 21h20
  3. [RegEx] je n'arrive pas à faire deux regex(s?)
    Par sloshy dans le forum Langage
    Réponses: 5
    Dernier message: 17/10/2005, 16h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo