Probleme de segment mémoire en C
encoremoi
-
loupius -
loupius -
Bonjour,
J'ai écrit un programme qui effectue la communication entre 3 processus via des segments de memoire partagee.
Le code marche, mais 1 seule fois...apres il ne marche plus.
Je pense que le probleme vient du segment mémoire, car si je change la clef du segment, le programme remarche...mais 1 seule fois.
il y a 3 programmes: le 1er saisit un nombre en binaire et l'ecrit dans le segment.
Le 2nd le convertit en decimal.
Le 3ieme le convertit en hexa.
Le 1er programme affiche le nombre dans les 3 formats.
Il y a une boucle pour faire l'opératon plusieurs fois.
La 1ere fois que je l'exécute, ca marche (mais le programme se ferme pas a la fin...)
Quand je l'exécute une 2nde fois, sans rien changer, il ne marche plus, seul le 1er programme affiche ce qu'il faut.
Si vous pouviez me dire quoi faire...
Prog1
------------
Prog2
------------
Prog3
Merci d'avance
J'ai écrit un programme qui effectue la communication entre 3 processus via des segments de memoire partagee.
Le code marche, mais 1 seule fois...apres il ne marche plus.
Je pense que le probleme vient du segment mémoire, car si je change la clef du segment, le programme remarche...mais 1 seule fois.
il y a 3 programmes: le 1er saisit un nombre en binaire et l'ecrit dans le segment.
Le 2nd le convertit en decimal.
Le 3ieme le convertit en hexa.
Le 1er programme affiche le nombre dans les 3 formats.
Il y a une boucle pour faire l'opératon plusieurs fois.
La 1ere fois que je l'exécute, ca marche (mais le programme se ferme pas a la fin...)
Quand je l'exécute une 2nde fois, sans rien changer, il ne marche plus, seul le 1er programme affiche ce qu'il faut.
Si vous pouviez me dire quoi faire...
Prog1
typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; void erreur(char *mes); void lire(int sig); SEGMENT *pSeg; int shmid ; int main(void) { int cle,pidB,pidC; char *argv[3]; char chpidC[10]; char bin[10]; cle=ftok("fic",'1'); shmid=shmget(cle,sizeof(SEGMENT),IPC_CREAT|0666); if(shmid==-1) erreur("pb creation de segment\n"); pSeg=(SEGMENT *)shmat(shmid,NULL,0); //creation du fils C pidC=fork(); if (pidC==0) execv("C9",NULL); //creation du fils B pidB=fork(); argv[0]="B9"; sprintf(chpidC,"%d",pidC); argv[1]=chpidC; argv[2]=NULL; if (pidB==0) execv("B9",argv); do { //saisie du nombre binaire printf("taper le nombre en binaire\n"); scanf("%s",pSeg->bin); printf("le nombre binaire dans A est %s\n",pSeg->bin); kill(pidB,SIGUSR1); signal(SIGUSR2,lire); pause(); }while(pSeg->nb!=0); shmdt(pSeg); shmctl(shmid,IPC_RMID,NULL); exit(0); } void lire(int sig) { printf("decimal =%d\n",pSeg->nb); printf("hexa =%s\n",pSeg->hex); printf("binaire =%s\n",pSeg->bin); }
------------
Prog2
typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; void erreur(char *mes); void lireEcrire(int sig); int puis2(int e); int traduire(char *bin); SEGMENT *pSeg; int pidC,shmid; int main(int argc, char *argv[]) { int cle; pidC = atoi(argv[1]); cle=ftok("fic",'1'); shmid=shmget(cle,sizeof(SEGMENT),SHM_RDONLY); if(shmid==-1) erreur("pb ouv de segment\n"); pSeg=(SEGMENT *)shmat(shmid,NULL,0); signal(SIGUSR1,lireEcrire); for(;;) pause(); exit(0); } void lireEcrire(int sig) { if(pSeg->nb!=0) { pSeg->nb=traduire(pSeg->bin); printf("le nombre decimal dans B est %d\n",pSeg->nb); //on dit a C de lire kill(pidC,SIGUSR1); } else { shmdt(pSeg); shmctl(shmid,IPC_RMID,NULL); exit(0); } }
------------
Prog3
typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; void erreur(char *mes); void lireEcrire(int sig); SEGMENT *pSeg; int pidC,shmid; int main(void) { int cle; cle=ftok("fic",'1'); shmid=shmget(cle,sizeof(SEGMENT),SHM_RDONLY); if(shmid==-1) erreur("pb ouv de segment\n"); pSeg=(SEGMENT *)shmat(shmid,NULL,0); signal(SIGUSR1,lireEcrire); for(;;) pause(); exit(0); } void lireEcrire(int sig) { if(pSeg->nb!=0) { //traduction du decimal en hexa sprintf(pSeg->hex,"%x",pSeg->nb); printf("le nombre hexa dans C est %s\n",pSeg->hex); //on envoie un signal a A pour lui dire de lire kill(getppid(),SIGUSR2); } else { shmdt(pSeg); shmctl(shmid,IPC_RMID,NULL); exit(0); } }
Merci d'avance
A voir également:
- Probleme de segment mémoire en C
- Mémoire vive - Guide
- RAM : type, format, CAS, vitesse, tout sur la mémoire vive - Guide
- Nettoyer memoire iphone - Guide
- C'est un secret bien gardé : ce réglage d'expert peut doper les performances de votre PC - Guide
- Mémoire virtuelle pour 32 go de ram - Guide
3 réponses
Bon, c'est encore moi!
J'ai quelque peu réécris le programme
Lors d'un récent post, je t'avais dit qu'après appel à 'fork(s)', il est indispensable d'attendre que les fils soient finis et de lire leur code de retour avant de terminer le programme... n'aurais-je pas été assez clair ?
D'autre part, il est indispensable, si l'on veut construire des programmes corrects, de gérer systématiquement les retours de certaines fonctions:
- supposons que l'appel 'fork' se passe mal et qu'il n'y a pas de fils créé, que se passe-t-il ?
- supposons que execv("C9", NULL); ne se passe pas bien, que se passe-t-il ? Le programme fils se poursuit par if (!(pidB = fork())) et imagine la pagaille.
Bonne réflexion.
J'ai quelque peu réécris le programme
Programme 1: ----------- typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; SEGMENT* pSeg; int shmid; void erreur(char *mes) { printf("%s\n", mes); exit(-1); } void lire(int sig) { printf(">>> decimal =%d\n", pSeg->nb); printf(">>> hexa =%s\n", pSeg->hex); printf(">>> binaire =%s\n", pSeg->bin); } int main(void) { int pidB, pidC; //creation du fils C if (!(pidC = fork())) { usleep(1000); // Pour permettre la création du segment partagé execv("C9", NULL); } //creation du fils B if (!(pidB = fork())) { usleep(1000); // Pour permettre la création du segment partagé char chpidC[10]; sprintf(chpidC, "%d", pidC); char* argv[3] = { "B9", chpidC, NULL }; execv("B9",argv); } int cle = ftok("fic", '1'); shmid = shmget(cle, sizeof(SEGMENT), IPC_CREAT|0666); if (shmid == -1) erreur("P1: pb creation de segment\n"); pSeg = (SEGMENT*)shmat(shmid, NULL, 0); signal(SIGUSR2, lire); do { printf("P1: taper le nombre en binaire\n"); scanf("%s", pSeg->bin); // On envoie un signal a B pour lui dire de lire kill(pidB, SIGUSR1); usleep(1000); // Attente pour synchro } while(pSeg->nb); shmdt(pSeg); shmctl(shmid, IPC_RMID, NULL); while (wait(NULL) > 0); return(0); } Programme 2: ----------- typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; SEGMENT* pSeg; int pidC, shmid; void erreur(char *mes) { printf("%s\n", mes); exit(-1); } void lireEcrire(int sig) { pSeg->nb = 0; int i = 0; while (pSeg->bin[i]) { pSeg->nb <<= 1; pSeg->nb += pSeg->bin[i++] - '0'; } printf("P2: le nombre decimal dans B est %d\n", pSeg->nb); // On envoie un signal a C pour lui dire de lire kill(pidC, SIGUSR1); if(!pSeg->nb) { // Nbre saisi nul -> on termine shmdt(pSeg); shmctl(shmid, IPC_RMID, NULL); exit(0); } } int main(int argc, char *argv[]) { pidC = atoi(argv[1]); int cle = ftok("fic", '1'); shmid = shmget(cle, sizeof(SEGMENT), SHM_RDONLY); if (shmid == -1) erreur("P2: pb ouv de segment\n"); pSeg = (SEGMENT*)shmat(shmid, NULL, 0); signal(SIGUSR1, lireEcrire); for (;;) pause(); return(0); } Programme 3: ----------- typedef struct { int nb; char bin[16]; char hex[16]; }SEGMENT; SEGMENT* pSeg; int pidC, shmid; void erreur(char *mes) { printf("%s\n", mes); exit(-1); } void lireEcrire(int sig) { if (pSeg->nb) { sprintf(pSeg->hex, "%x", pSeg->nb); printf("P3: le nombre hexa dans C est %s\n", pSeg->hex); // On envoie un signal a A pour lui dire de lire kill(getppid(), SIGUSR2); } else { // Nbre saisi nul -> on termine shmdt(pSeg); shmctl(shmid, IPC_RMID,NULL); exit(0); } } int main(void) { int cle = ftok("fic", '1'); shmid = shmget(cle, sizeof(SEGMENT), SHM_RDONLY); if (shmid == -1) erreur("P3: pb ouv de segment\n"); pSeg = (SEGMENT*)shmat(shmid, NULL, 0); signal(SIGUSR1, lireEcrire); for (;;) pause(); return(0); }Tu as sans doute remarqué que j'ai introduit quelques 'sleep' pour des raisons de synchronisation. En effet, l'accès à des ressources partagées se font normalement sous le contrôle de sémaphores; ce sera peut-être le prochain exercice que tu nous proposeras de corriger ;-)))
Lors d'un récent post, je t'avais dit qu'après appel à 'fork(s)', il est indispensable d'attendre que les fils soient finis et de lire leur code de retour avant de terminer le programme... n'aurais-je pas été assez clair ?
D'autre part, il est indispensable, si l'on veut construire des programmes corrects, de gérer systématiquement les retours de certaines fonctions:
- supposons que l'appel 'fork' se passe mal et qu'il n'y a pas de fils créé, que se passe-t-il ?
- supposons que execv("C9", NULL); ne se passe pas bien, que se passe-t-il ? Le programme fils se poursuit par if (!(pidB = fork())) et imagine la pagaille.
Bonne réflexion.
merci loupius !
"Lors d'un récent post, je t'avais dit qu'après appel à 'fork(s)', il est indispensable d'attendre que les fils soient finis et de lire leur code de retour avant de terminer le programme..."
-> c'est vrai... c'est grace aux sleep, en attendant que les fils soient finis, que vous faites ca ?
Le code que j'avais initialement marchait mais 1 seule fois ??? Comment peut on l'expliquer ? Est ce du au fait que je n'attendais pas la mort du fils ? (j'etais oblige de faire ctrl+C pour l'arreter...mais apres un ps ne me disait pas que les fils restaient ouverts...)
Enfin, qu'est ce que le "<<=" dans le prog 2 ?
Merci encore
"Lors d'un récent post, je t'avais dit qu'après appel à 'fork(s)', il est indispensable d'attendre que les fils soient finis et de lire leur code de retour avant de terminer le programme..."
-> c'est vrai... c'est grace aux sleep, en attendant que les fils soient finis, que vous faites ca ?
Le code que j'avais initialement marchait mais 1 seule fois ??? Comment peut on l'expliquer ? Est ce du au fait que je n'attendais pas la mort du fils ? (j'etais oblige de faire ctrl+C pour l'arreter...mais apres un ps ne me disait pas que les fils restaient ouverts...)
Enfin, qu'est ce que le "<<=" dans le prog 2 ?
Merci encore
Bon, y'a encore des explications à donner ;-)
### x <<= y : '<<' est l'opérateur de décalage à gauche, donc <<= décale l'opérande 'x' de 'y' fois; en l'occurence, ici, on décale 1 fois ce qui revient à multiplier l'entier par 2.
### Non, on attend que les fils soient finis par while (wait(NULL) > 0);
### mais apres un ps ne me disait pas que les fils restaient ouverts, c'est là qu'intervient l'intelligence des concepteurs. Normalement, lorsque le fils se termine, il devient 'zombie en attendant que son père lise son code de retour (tant que le père n'est pas fini, un 'ps' t'indiquera que le fils existe toujours) et si le père se termine sans lire le code de retour, le fils qui était attaché à son père ne peut plus l'être et comme tout processus à un père, le fils est alors attaché au processus 'init' (d'ailleurs le seul qui n'a pas de père, eh oui il en faut bien un !) qui, à la place du père, lit le code de retour ce qui fait disparaître définitivement le fils.
### A propos de la synchronisation: il faut bien comprendre que les différents processus ne 'tournent' pas en même temps (oui, je sais qu'il y a des multi-coeurs mais de toutes façons il y a des limites, si vous avez huit coeurs et vingt process, tout le monde ne peut tourner en même temps), donc pour des opérations particulières il est important de s'assurer que les opérations seront exécutées dans un certain ordre. Par exemple, étant donné que l'on a choisi que le père crée le segment partagé, il est important que les fils ne l'ouvrent qu'après; or, lorsque le 'fork' se produit, un processus est créé; alors deux processus existent et on est incapable de prévoir quel processus se poursuivra avant l'autre. Il faut donc attendre un 'certain temps' avant d'ouvrir la mémoire partagée. Evidemment, le mieux, pour gérer la synchronisation, est le système de sémaphores. Et si ton code ne marchait pas bien, c'était dû justement à un problème de synchro.
Bonne réflexion.
### x <<= y : '<<' est l'opérateur de décalage à gauche, donc <<= décale l'opérande 'x' de 'y' fois; en l'occurence, ici, on décale 1 fois ce qui revient à multiplier l'entier par 2.
### Non, on attend que les fils soient finis par while (wait(NULL) > 0);
### mais apres un ps ne me disait pas que les fils restaient ouverts, c'est là qu'intervient l'intelligence des concepteurs. Normalement, lorsque le fils se termine, il devient 'zombie en attendant que son père lise son code de retour (tant que le père n'est pas fini, un 'ps' t'indiquera que le fils existe toujours) et si le père se termine sans lire le code de retour, le fils qui était attaché à son père ne peut plus l'être et comme tout processus à un père, le fils est alors attaché au processus 'init' (d'ailleurs le seul qui n'a pas de père, eh oui il en faut bien un !) qui, à la place du père, lit le code de retour ce qui fait disparaître définitivement le fils.
### A propos de la synchronisation: il faut bien comprendre que les différents processus ne 'tournent' pas en même temps (oui, je sais qu'il y a des multi-coeurs mais de toutes façons il y a des limites, si vous avez huit coeurs et vingt process, tout le monde ne peut tourner en même temps), donc pour des opérations particulières il est important de s'assurer que les opérations seront exécutées dans un certain ordre. Par exemple, étant donné que l'on a choisi que le père crée le segment partagé, il est important que les fils ne l'ouvrent qu'après; or, lorsque le 'fork' se produit, un processus est créé; alors deux processus existent et on est incapable de prévoir quel processus se poursuivra avant l'autre. Il faut donc attendre un 'certain temps' avant d'ouvrir la mémoire partagée. Evidemment, le mieux, pour gérer la synchronisation, est le système de sémaphores. Et si ton code ne marchait pas bien, c'était dû justement à un problème de synchro.
Bonne réflexion.