tableau de chaines en mémoire partagé (Linux/POSIX) [RESOLU]

tableau de chaines en mémoire partagé (Linux/POSIX) [RESOLU] - C - Programmation

Marsh Posté le 18-05-2007 à 12:29:08    

Bonjour à tous
J'en appel au programmeurs c pour qui l'algèbre des pointeurs n'a plus de secrets  :)  
Pour un devoirs je doit réaliser un tchat, sous Linux, qui utilise les IPC, Sémaphores et mémoire partagé pour communiquer, jusque la, pas de problème. mais lorsqu'il s'agit de stocker la liste des pseudo des connectés à mon tchat, impossible de réaliser un code qui fonctionne. J'ai déjà codé en C il y a quelques années mais la, impossible de trouver la bonne combinaison de *,&, **truc et autres *(char)(truc[i]) qui fonctionne  :D , je deviens fou.
 
Ce que je souhaite faire : un tableau qui stocke la liste des surnom de mes utilisateurs, qui sera en mémoire partagé.
 
Je vous donne le code que j'ai déja réalisé mais sur lequel je n'arrive pas à travailler sans provoquer un "segmentation fault"
 

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <sys/shm.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #define NMAXCLI  3
  11. #define LONGPSEUDO 40
  12. #define SEMPSEUDO   0
  13. #define PSEUDO    0
  14. key_t   kCle[2] ;
  15. int     iSemid ;
  16. int     iShmid[1] ;
  17. struct sembuf sSembufSemaphore ;
  18. char **  pcSegMemPseudo;
  19. int main (int argc, char *argv[]){
  20.   int i ;
  21.   /* inititalisations IPC */
  22.   kCle[0] = ftok (argv[1],0);
  23.   kCle[1] = ftok (argv[1],1);
  24. /* Sémaphores */
  25.   iSemid = semget (kCle[0],1,IPC_CREAT|0666) ;
  26.   semctl (iSemid,SEMPSEUDO,SETVAL,1) ;
  27. /* Segment mémoire pour les pseudo */
  28.   iShmid[PSEUDO] = shmget (kCle[1],(int)((NMAXCLI*sizeof(char *))+(NMAXCLI*((LONGPSEUDO+1)*sizeof(char)))),IPC_CREAT|0666) ;
  29.   pcSegMemPseudo = (char **) shmat (iShmid[PSEUDO],NULL,0) ;
  30.   fprintf (stderr,"pcSegMemPseudo : 0x%p\n",pcSegMemPseudo) ;
  31.   /* Prise du sémaphore SEMPSEUDO */
  32.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  33.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  34.   sSembufSemaphore.sem_op  = -1 ;         /* P(s) */
  35.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel P(s) */
  36.   /* initialisation de mon tableau avec toto */
  37.   char * toto = "toto";
  38.   for (i=0;i<NMAXCLI;i++) strcpy(pcSegMemPseudo [i], toto) ;
  39.   /* lecture du tableau */
  40.   for (i=0;i<NMAXCLI;i++) fprintf (stderr,"login %d : %s\n", i, pcSegMemPseudo[i]);
  41.   /* Libération du sémaphore SEMPSEUDO */
  42.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  43.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  44.   sSembufSemaphore.sem_op  =  1 ;         /* V(s) */
  45.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel V(s) */
  46. return EXIT_SUCCESS ;
  47. }


 
un fichier key doit etre créer (touche key) pour permetre la génération des clés pour identifier les sémaphores et segment partagés.
 
une fois compilé, il suffit de lancer ./test key
 
Je pense que l'allocation de l'espace mémoire est bonne car elle représente bien ce que je souhaite faire :
 (NMAXCLI * taille d'un pointeur sur char) + (NMAXCLI * taille max d'un pseudo)
réctiffiez moi si je me trompe
 
L'écriture provoque évidement une erreure de ségmentation car je doit mal m'y prendre, j'ai essayé beaucoup de combinaisons mais sans trouver la bonne.
 
merci pour vos conseils
 
Cyril

Message cité 1 fois
Message édité par misterpatate le 20-05-2007 à 17:28:58

---------------
Le HTML c'est pour les papys, passez à OpenLaszlo : http://www.misterpatate.fr
Reply

Marsh Posté le 18-05-2007 à 12:29:08   

Reply

Marsh Posté le 18-05-2007 à 13:32:13    

quelle est la valeur de retour de shmget ?

Reply

Marsh Posté le 18-05-2007 à 13:41:24    

 for (i=0;i<NMAXCLI;i++) strcpy(pcSegMemPseudo [i], toto) ;
 
pcSegMemPseudo [i] ne sont pas initialisés.

Reply

Marsh Posté le 18-05-2007 à 13:55:45    

shmget renvoi un entier qui identifie le segment de mémoire partagé.
 
comment initialiser  pcSegMemPseudo [i] ?  
J'ai vu des exemples de création de tableaux à 2 dimensions mais à chaque fois il étais associés à des malloc(), ici je pense avoir alloué toute la mémoire nécessaire pour mon tableau (âpres peut être que je mélange tout).  
Je suis d'accord pour dire qu'il manque quelque chose pour définir la structure de mon tableau mais je ne sais pas comment m'y prendre.

Reply

Marsh Posté le 18-05-2007 à 14:37:02    

misterpatate a écrit :

shmget renvoi un entier qui identifie le segment de mémoire partagé.

surtout en cas d'erreur ...

misterpatate a écrit :


comment initialiser  pcSegMemPseudo [i] ?  
J'ai vu des exemples de création de tableaux à 2 dimensions mais à chaque fois il étais associés à des malloc(), ici je pense avoir alloué toute la mémoire nécessaire pour mon tableau (âpres peut être que je mélange tout).  
Je suis d'accord pour dire qu'il manque quelque chose pour définir la structure de mon tableau mais je ne sais pas comment m'y prendre.


Tu mélanges tout. Apprend d'abord à le faire avec malloc.

Reply

Marsh Posté le 18-05-2007 à 15:08:25    

Taz a écrit :


surtout en cas d'erreur ...  


pour ce code j'ai bien en retours mon identifiant de segment partagé (vérifié avec strace )
mais en cas d'erreur il renvoi -1
 

Taz a écrit :


Tu mélanges tout.


Je sais, c'est bien le problème mentionné en introduction.
 

Taz a écrit :


 Apprend d'abord à le faire avec malloc.


 
J'ai déjà abordé toutes les méthodes de création de tableau de chaines avec plusieurs tutoriels, cependant je n'ai réussi à appliquer aucune d'elles avec mon espace mémoire partagé, c'est pour cela que je pose la question pour ce cas précis.
 
comment ferais tu ?

Reply

Marsh Posté le 18-05-2007 à 16:09:28    

Je ferais pareil qu'avec malloc. Ou alors une allocation en une seule fois. Tout pareil qu'avec malloc. Aucune différence de qui te fournit un emplacement libre.

Reply

Marsh Posté le 20-05-2007 à 14:00:19    

misterpatate a écrit :

J'ai déjà abordé toutes les méthodes de création de tableau de chaines avec plusieurs tutoriels, cependant je n'ai réussi à appliquer aucune d'elles avec mon espace mémoire partagé, c'est pour cela que je pose la question pour ce cas précis.
 
comment ferais tu ?


Comme le dit Taz, si tu sais le faire avec malloc (qui te renvoie un pointeur sur une zone d'octets alloués en mémoire), tu sais le faire avec shmat (qui te renvoie un pointeur sur une zone d'octets alloués en mémoire partagée)
 

misterpatate a écrit :

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <sys/shm.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #define NMAXCLI  3
  11. #define LONGPSEUDO 40
  12. #define SEMPSEUDO   0
  13. #define PSEUDO    0
  14. key_t   kCle[2] ;
  15. int     iSemid ;
  16. int     iShmid[1] ;
  17. struct sembuf sSembufSemaphore ;
  18. char **  pcSegMemPseudo;
  19. int main (int argc, char *argv[]){
  20.   int i ;
  21.   /* inititalisations IPC */
  22.   kCle[0] = ftok (argv[1],0);
  23.   kCle[1] = ftok (argv[1],1);
  24. /* Sémaphores */
  25.   iSemid = semget (kCle[0],1,IPC_CREAT|0666) ;
  26.   semctl (iSemid,SEMPSEUDO,SETVAL,1) ;
  27. /* Segment mémoire pour les pseudo */
  28.   iShmid[PSEUDO] = shmget (kCle[1],(int)((NMAXCLI*sizeof(char *))+(NMAXCLI*((LONGPSEUDO+1)*sizeof(char)))),IPC_CREAT|0666) ;
  29.   pcSegMemPseudo = (char **) shmat (iShmid[PSEUDO],NULL,0) ;
  30.   fprintf (stderr,"pcSegMemPseudo : 0x%p\n",pcSegMemPseudo) ;
  31.   /* Prise du sémaphore SEMPSEUDO */
  32.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  33.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  34.   sSembufSemaphore.sem_op  = -1 ;         /* P(s) */
  35.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel P(s) */
  36.   /* initialisation de mon tableau avec toto */
  37.   char * toto = "toto";
  38.   for (i=0;i<NMAXCLI;i++) strcpy(pcSegMemPseudo [i], toto) ;
  39.   /* lecture du tableau */
  40.   for (i=0;i<NMAXCLI;i++) fprintf (stderr,"login %d : %s\n", i, pcSegMemPseudo[i]);
  41.   /* Libération du sémaphore SEMPSEUDO */
  42.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  43.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  44.   sSembufSemaphore.sem_op  =  1 ;         /* V(s) */
  45.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel V(s) */
  46. return EXIT_SUCCESS ;
  47. }



A mon avis, l'erreur vient de la ligne 51. Tu copies ton pseudo dans "pcSegMemPseudo[i]" qui n'est pas une chaîne de caractères mais un simple pointeur. Total, lors de l'itération suivante, le pseudo suivant est copié dans l'adresse qui est juste à coté et non celle qui est au début de la string suivante
Ex: Ta zone commence à l'adresse "0x1000". Tu itères ta copie de "toto". Tu aimerais avoir

  • 't', 'o', 't', 'o', '\0' n° 1qui vient se copier dans les cases 0x1000, 0x1001, 0x1002, 0x1003 et 0x1004
  • 't', 'o', 't', 'o', '\0' n° 2 qui vient se copier dans les cases 0x1005, 0x1006, 0x1007, 0x1008 et 0x1009

Mais comme tu ne travailles qu'avec des pointeurs, tu as en fait

  • 't', 'o', 't', 'o', '\0' n° 1qui vient se copier dans les cases 0x1000, 0x1001, 0x1002, 0x1003 et 0x1004
  • 't', 'o', 't', 'o', '\0' n° 2 qui vient se copier dans les cases 0x1001, 0x1002, 0x1003, 0x1004 et 0x1005


Pour t'en sortir, soit tu fais toi-même les calculs de positionnement corrects dans le gros tableau de char "pcSegMemPseudo", soit tu travailles avec des tableaux de strings (en utilisant LONGPSEUDO)


Message édité par Sve@r le 20-05-2007 à 14:13:05

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 20-05-2007 à 17:28:01    

merci pour ces indications, j'ai ainsi pue obtenir un code fonctionnel que voici :

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <sys/shm.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #define NMAXCLI  3
  11. #define SEMPSEUDO   0
  12. #define LONGPSEUDO 40
  13. #define TPSEUDO    0
  14. #define VECPSEUDO    1
  15. key_t   kCle[3] ;
  16. int     iSemid ;
  17. int     iShmid[2] ;
  18. struct sembuf sSembufSemaphore ;
  19. char *vecPseudo;
  20. char ** pcSegMemPseudo;
  21. int main (int argc, char *argv[]){
  22.   int i ;
  23.  
  24.   /* inititalisations IPC */
  25.   kCle[0] = ftok (argv[1],0);
  26.   kCle[1] = ftok (argv[1],1);
  27.   kCle[2] = ftok (argv[1],2);
  28. /* Sémaphores */
  29.   iSemid = semget (kCle[0],1,IPC_CREAT|0666) ;
  30.   semctl (iSemid,SEMPSEUDO,SETVAL,1) ;
  31.   /* Segment mémoire pour le vecteur de pseudo */
  32.   iShmid[VECPSEUDO] = shmget (kCle[1],(int)((LONGPSEUDO+1) * NMAXCLI * sizeof(*vecPseudo)),IPC_CREAT|0666) ;
  33.   vecPseudo = (char *) shmat (iShmid[VECPSEUDO],NULL,0) ;
  34.   fprintf (stderr,"vecPseudo : 0x%p\n",vecPseudo) ;
  35.   /* Segment mémoire pour le tableau de pseudo */
  36.   iShmid[TPSEUDO] = shmget (kCle[2],(int)(NMAXCLI * sizeof(*pcSegMemPseudo)),IPC_CREAT|0666) ;
  37.   pcSegMemPseudo = (char **) shmat (iShmid[TPSEUDO],NULL,0) ;
  38.   fprintf (stderr,"pcSegMemPseudo : 0x%p\n",pcSegMemPseudo) ;
  39.   /* initialisation du tableau pcSegMemPseudo */
  40.   for (i=0;i<NMAXCLI;i++)
  41. pcSegMemPseudo[i] = vecPseudo+ i * (LONGPSEUDO+1);
  42.   /* Prise du sémaphore SEMPSEUDO */
  43.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  44.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  45.   sSembufSemaphore.sem_op  = -1 ;         /* P(s) */
  46.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel P(s) */
  47.   /* initialisation de mon tableau avec toto */
  48.   char * toto = "toto";
  49.   for (i=0;i<NMAXCLI;i++) strcpy(pcSegMemPseudo[i], toto) ;
  50.                
  51.   /* lecture du tableau */
  52.   for (i=0;i<NMAXCLI;i++) printf("login %d : %s\n", i, pcSegMemPseudo[i]);
  53.   /* Libération du sémaphore SEMPSEUDO */
  54.   sSembufSemaphore.sem_num =  SEMPSEUDO ;  /* sémaphore SEMLISTE */
  55.   sSembufSemaphore.sem_flg =  0 ;         /* blocant */
  56.   sSembufSemaphore.sem_op  =  1 ;         /* V(s) */
  57.   semop (iSemid,&sSembufSemaphore,1) ;    /* Appel V(s) */
  58. return EXIT_SUCCESS ;
  59. }

Reply

Marsh Posté le 20-05-2007 à 17:40:50    

Oui. Tu peux éviter d'avoir 3 clefs distinctes et n'en utiliser qu'une seule en gérant bien le positionnement dans ta shm.
Sinon il me semble que la seconde valeur de ftok() ne doit pas être égale à 0 donc ta ligne 37 devrait merder...
Moi, quand je fais du ftok, j'utilise "." comme nom de fichier et getuid() comme second paramètre. Ca permet donc d'avoir des clefs différentes suivant

  • l'endroit où on se trouve
  • celui qui lance le programme


Et permet aussi d'avoir la même clef si les paramètres sont identiques

Code :
  1. ftok(".", (getuid() & 0xff) != 0 ?getuid() :-1)


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 20-05-2007 à 17:40:50   

Reply

Marsh Posté le 20-05-2007 à 18:18:21    

merci pour ces précisions.
j'utilise la valeur 0 pour ftok depuis pas mal de temps et ça ne semble pas poser de problème.

Reply

Marsh Posté le 20-05-2007 à 18:53:46    

misterpatate a écrit :

j'utilise la valeur 0 pour ftok depuis pas mal de temps et ça ne semble pas poser de problème.


 
Faudra que je vérifie. Un des man ne dit rien sur ça (http://www.linux-kheops.com/doc/ma [...] tok.3.html) mais l'autre le précise (http://man.cx/ftok(3)/fr)
Mais une chose est certaine => ftok associe les bits à "1" de la valeur avec les bits de poids faibles du n° d'inode du fichier qu'on lui donne. Donc une valeur à 0 ne sert à rien...
 
Sinon moi j'aurais créé une grosse structure pour gérer tout le projet (elle contient les pseudos et tout le reste) puis j'aurais benné ma structure d'un coup en shm via un bon gros memcpy bien bestial. A voir...


Message édité par Sve@r le 20-05-2007 à 18:54:26

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 21-05-2007 à 00:08:07    

bof, c'est très très compliqué ton truc. Il faut réfléchir un peu des fois. Une méthode plus simple et plus efficace et demandant moins de mémoire est (exemple avec malloc) :

 
Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #define TAILLEPSEUDO 10
  4. int main()
  5. {
  6.         char (*p)[TAILLESPEUDO];
  7.         size_t n = 42;
  8.         p = malloc(n * sizeof *p);
  9.         printf("sizeof *p = %u\n", sizeof *p);
  10.         free(p);
  11.         return 0;
  12. }
 

Et voilà !


Message édité par Taz le 21-05-2007 à 00:10:28
Reply

Marsh Posté le 21-05-2007 à 00:12:18    

et d'ailleurs dans ton histoire, ou toutes les dimensions du tableau sont connus, c'est encore plus simple

 
Code :
  1. char (*p)[NMAXCLI][TAILLEPSEUDO];
  2.         p = malloc(sizeof *p);
 

et donc tu fais le tout en une seule allocation, un seul segment


Message édité par Taz le 21-05-2007 à 00:13:18
Reply

Marsh Posté le 25-05-2007 à 18:57:59    

misterpatate a écrit :

j'utilise la valeur 0 pour ftok depuis pas mal de temps et ça ne semble pas poser de problème.


J'ai regardé aujourd'hui au bureau (j'avais un peu zappé le truc puis je m'en suis rappelé).
Donc dans un premier temps, ftok(..., 0) a marché (il m'a renvoyé une valeur qui n'était pas "-1" ). Mais en lisant attentivement le man, c'était écrit explicitement "...utiliser une valeur à 0 provoque un comportement indéfini" => c.a.d. que ça peut très bien fonctionner 12 fois et planter à la 13°...
http://man.developpez.com/man3/ftok.3.php


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 25-05-2007 à 21:35:35    

merci pour cette précision qui explique probablement quelques plantages lors de mes test ;)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed