Probleme de segment mémoire en C

Fermé
encoremoi - 26 août 2009 à 20:42
 loupius - 28 août 2009 à 01:36
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
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

3 réponses

Bon, c'est encore moi!
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.
0
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
0
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.
0
merci loupius

les semaphores je vais justement les aborder bientot... mais j'attendais de maitriser un peu les segments avant...
0
Ah je me doutais bien qu'après les exercices sur les 'fork' et la 'mémoire partagée', on aurait droit (voir réponse n° 1) aux sémaphores ;-)))
A plus tard.
0