Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2984 connectés 

  FORUM HardWare.fr
  Programmation
  C

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

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

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

n°1561985
misterpata​te
Posté le 18-05-2007 à 12:29:08  profilanswer
 

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
mood
Publicité
Posté le 18-05-2007 à 12:29:08  profilanswer
 

n°1562023
Taz
bisounours-codeur
Posté le 18-05-2007 à 13:32:13  profilanswer
 

quelle est la valeur de retour de shmget ?

n°1562026
Taz
bisounours-codeur
Posté le 18-05-2007 à 13:41:24  profilanswer
 

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

n°1562034
misterpata​te
Posté le 18-05-2007 à 13:55:45  profilanswer
 

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.

n°1562059
Taz
bisounours-codeur
Posté le 18-05-2007 à 14:37:02  profilanswer
 

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.

n°1562085
misterpata​te
Posté le 18-05-2007 à 15:08:25  profilanswer
 

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 ?

n°1562117
Taz
bisounours-codeur
Posté le 18-05-2007 à 16:09:28  profilanswer
 

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.

n°1562613
Sve@r
Posté le 20-05-2007 à 14:00:19  profilanswer
 

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.
n°1562645
misterpata​te
Posté le 20-05-2007 à 17:28:01  profilanswer
 

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. }

n°1562648
Sve@r
Posté le 20-05-2007 à 17:40:50  profilanswer
 

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.
mood
Publicité
Posté le 20-05-2007 à 17:40:50  profilanswer
 

n°1562650
misterpata​te
Posté le 20-05-2007 à 18:18:21  profilanswer
 

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.

n°1562659
Sve@r
Posté le 20-05-2007 à 18:53:46  profilanswer
 

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.
n°1562726
Taz
bisounours-codeur
Posté le 21-05-2007 à 00:08:07  profilanswer
 

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
n°1562727
Taz
bisounours-codeur
Posté le 21-05-2007 à 00:12:18  profilanswer
 

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
n°1565425
Sve@r
Posté le 25-05-2007 à 18:57:59  profilanswer
 

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.
n°1565456
misterpata​te
Posté le 25-05-2007 à 21:35:35  profilanswer
 

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


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

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

 

Sujets relatifs
Visual Basic : copier le contenu d'une liste dans un tableau[Résolu] Problème polymorphisme et sous typage
Installer java sous linux[Ocaml] lecture d'un fichier texte de > 50 Mo (resolu)
[VB/TSQL/SQL-Server] Mes questions sur les Procédures stockéesLabview: problème pour créer un tableau
clonage d'un tableau simpleTableau croisé dynamique : faire une "joiture" sur 2 feuilles
[RESOLU] ant build.xml LD_LIBRARY_PATHJava et linux (dos2linux)
Plus de sujets relatifs à : tableau de chaines en mémoire partagé (Linux/POSIX) [RESOLU]


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR