Probleme de synchronisation

Fermé
encoremoi - 19 août 2009 à 20:06
 loupius - 21 août 2009 à 23:43
Bonjour,

J'essaie d'écrire un programme en C avec des pipes, amsi j'ai des problemes de syncronisation car quand je lance le programme, l'ordinateur "attend"...

Si vous pouviez me débloquer, et surtout m'expliquer pourquoi ca bloque...
(notamment, pourquoi mon printf("salut\n"); n'affiche rien, il est au tout début du programme pourtant ?)

prog1
void erreur(char *mes);
void lecture(int sig);

int main(void)
{
	int pid,dp;
	char mot[10]="hello";
printf("salut\n");
	//creation du pipe
	unlink("pipe");
	mkfifo("pipe",0666);
printf("salut2\n");	
	//creation du fils
	pid=fork();
	if (pid==0)
		execv("prog2",NULL);

	//ouverture du pipe
	dp=open("pipe",O_WRONLY);
	if(dp==0) erreur("pb ouverture du pipe 1");

	//ecriture dans le pipe (envoi du 1er message)
	write(dp,&mot,sizeof(mot)+1);
	close(dp);

	signal(SIGUSR1,lecture);

	for(;;)
	{
		pause();
	}

	
	exit(0);
}

void lecture(int sig)
{
	int dp3,re;
	char ans[20];

	dp3=open("pipe3",O_RDONLY);
		if(dp3==0) erreur("pb ouverture du pipe 3");
	re=read(dp3,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe 3");
	printf("le resultat 3est\n");
	printf("egal à %s\n",ans);
	close(dp3);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}




prog2
void erreur(char *mes);

int main(void)
{
	int dp,dp2,re,pid5;
	char ans[20];
	char suite[15]="touslemonde";
	char *pidpere;
	
	sprintf(pidpere ,"%d", getppid());
	printf("hello");

	pid5=fork();
	if (pid5==0)
		execv("prog2",&pidpere);	

	//ouverture du pipe
	dp=open("pipe",O_RDONLY);
		if(dp==0) erreur("pb ouverture du pipe 1");
		
	//lecture
	re=read(dp,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe 1");
	printf("le resultat est\n");
	printf("egal à %s\n",ans);

	close (dp);

	//modification du message	
	int i=0;
	while(ans[i]!='\0')
		i++;	

	int j=0;
	while(suite[j]!='\0')
	{
		ans[i+j]=suite[j];
		j++;
	}
	strcpy(&ans[i+j],"\0");

	//ouverture du 2nd pipe
	dp2=open("pipe2",O_WRONLY);
		if(dp2==0) printf("pb ouverture du pipe 2");
	
	//envoi du signal a exolibre5 pour oub=vrir l'autre cote du pipe
	kill(pid5,SIGUSR2);

	//ecriture dans le pipe	
	write(dp2,&ans,sizeof(ans)+1);
	close(dp2);
	
	exit(0);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}




prog3
void erreur(char *mes);
void modif(int sig);
int pid_gp;

int main(int argc, char *argv[])
{
	pid_gp=atoi(argv[1]);
	printf("le pid du gd pere est %d\n",pid_gp);
	signal(SIGUSR2,modif);

	for(;;)
	{
		pause();
	}

	
	
	exit(0);
}

void modif(int sig)
{
	int dp2,re,dp3;
	char ans[20];
	char suite[15]="oui";

	//ouverture du pipe
	dp2=open("pipe2",O_RDONLY);
		if(dp2==0) erreur("pb ouverture du pipe 2");
		
	//lecture
	re=read(dp2,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe");
	printf("le resultat chez 5 est\n");
	printf("egal à %s\n",ans);
	close (dp2);

	//modification du message	
	int i=0;
	while(ans[i]!='\0')
		i++;	

	int j=0;
	while(suite[j]!='\0')
	{
		ans[i+j]=suite[j];
		j++;
	}
	strcpy(&ans[i+j],"\0");

	//ouverture du pipe pour parler a 1
	dp3=open("pipe3",O_WRONLY);
		if(dp3==0) erreur("pb ouverture du pipe 3");	
	
	//envoie du signal pour dire d'ouvrir l'autre cote du pipe
	kill(pid_gp,SIGUSR1);

	//ecriture dans le pipe
	write(dp3,&ans,sizeof(ans)+1);
	close(dp3);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}




Merci !

6 réponses

Je n'ai pas pris le temps de démonter tout le programme , mais quelques remarques me viennent:
- write(dp,&mot,sizeof(mot)+1);, non il faut mettre 'strlen(mot)' car sizeof(mot)+1 donnera 11 et ce n'est pas ce que tu veux.
- for(;;) { pause(); }, 'pause()' est inutile.
- while(suite[j]!='\0') est identique à ' while(suite[j])'
- As-tu fait attention au fait que l'ouverture d'un pipe en lecture est bloquante tant qu'un autre processus ne l'a pas ouvert en écriture et lycée de versailles! En conséquence, la séquence suivante ne devrait pas fonctionner:
//ouverture du pipe pour parler à 1
  dp3 = open("pipe3", O_WRONLY);
  if (!dp3)
    erreur("pb ouverture du pipe 3");
//envoi du signal pour dire d'ouvrir l'autre côté du pipe
  kill(pid_gp, SIGUSR1);

- re=read(dp3,ans,sizeof(ans)); printf("egal à %s\n",ans); rien ne dit que 'ans' sera terminé par un '\0'
- execv("prog2",&pidpere); heu, ce ne serait pas plutôt 'prog3',
Beaucoup d'imprécisions et je m'arrête là, ... et il n'est guère surprenant que le programme ne fait pas ce que l'on attend de lui mais seulement ... ce qu'on lui a demandé.
Je te souhaite beaucoup de persévérance.
NB: "touslemonde" s'écrit "tout le monde" ;-)
0
"- execv("prog2",&pidpere); heu, ce ne serait pas plutôt 'prog3',"
-> oui effectivement

"- re=read(dp3,ans,sizeof(ans)); printf("egal à %s\n",ans); rien ne dit que 'ans' sera terminé par un '\0'"
-> pourquoi ? le caractère de terminaison d'un mot n'est il pas \0 ?

effectivement "tout le monde" et pas "tous le monde".

Quand vous dites que la séquence suivant ne peux pas fonctionner :
//ouverture du pipe pour parler à 1
dp3 = open("pipe3", O_WRONLY);
if (!dp3)
erreur("pb ouverture du pipe 3");
//envoi du signal pour dire d'ouvrir l'autre côté du pipe
kill(pid_gp, SIGUSR1);

c'est parce que kill est apres open ?
il faudrait mettre le kill avant le open c'est bien ca ?

Merci d'avoir pris le temps de jeter un oeil a mon programme qui, il est vrai est un peu long a relire...
0
pourquoi ? le caractère de terminaison d'un mot n'est il pas \0 ?
Si le caractère de terminaison, par convention en C est '\0', mais encore faut-il le mettre! Et la fonction 'read(dp3,ans,sizeof(ans))' n'assure pas que 'ans' se terminera par un '\0' mais simplement, du fait du 'sizeof' qu'il n'y aura pas de débordement au-delà de 'ans'.

il faudrait mettre le kill avant le open c'est bien ca ?
Oui, car 'open' en écriture attendra que le tube nommé soit ouvert en lecture sauf s'il il y a une erreur d'ouverture. Lire ceci ou cela.
Bonne continuation.
0
Re-bonjour,
j'ai fait des petits changements, et je crois avoir identifié où ca blqoue, mais je ne sais pas pourquoi...

ca bloque apparemment au niveau du sprinf dans le 2nd programme


Prog1
int main(void)
{
	int pid,dp;
	char mot[10]="hello";

	//creation du pipe
	unlink("pipe");
	mkfifo("pipe",0666);
	
	//creation du fils
	pid=fork();
	if (pid==0)
		execv("prog2",NULL);

	//ouverture du pipe
	dp=open("pipe",O_WRONLY);
	if(dp==0) erreur("pb ouverture du pipe 1");
printf("ouv 1er pipe\n");
	//ecriture dans le pipe (envoi du 1er message)
	write(dp,&mot,strlen(mot));

	//fermeture du pipe
	close(dp);

	signal(SIGUSR1,lecture);

	for(;;)
	{
		pause();
	}

	
	exit(0);
}

void lecture(int sig)
{
	int dp3,re;
	char ans[20];

	dp3=open("pipe3",O_RDONLY);
		if(dp3==0) erreur("pb ouverture du pipe 3");
	re=read(dp3,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe 3");
	printf("le resultat 3 est\n");
	printf("egal à %s\n",ans);
	
	usleep(500);
	close(dp3);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}




Prog2
int main(void)
{
	int dp,dp2,re,pid5;
	char ans[20];
	char suite[15]="toutlemonde";
	char *pidpere;

	unlink("pipe2");
	mkfifo("pipe2",0666);	

	//ouverture du pipe
	dp=open("pipe",O_RDONLY);
		if(dp==0) erreur("pb ouverture du pipe 1");
printf("ouverture autre cote pipe1\n");

	//lecture
	re=read(dp,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe 1");
	printf("le resultat est\n");
	printf("egal à %s\n",ans);
printf("avant fermeture dans 2\n");
	usleep(500); //on attend que 1 ecrive dans le pipe
	close (dp);
printf("apres fermeture\n");
	sprintf(pidpere ,"%d", getppid());
	
printf("apres sprintf\n");
	pid5=fork();
	if (pid5==0)
		execv("prog3",&pidpere);	

	//modification du message	
	int i=0;
	while(ans[i]!='\0')
		i++;	

	int j=0;
	while(suite[j]!='\0')
	{
		ans[i+j]=suite[j];
		j++;
	}
	strcpy(&ans[i+j],"\0");

	//envoi du signal a prog3 pour ouvrir l'autre cote du pipe
	kill(pid5,SIGUSR2);	

	//ouverture du 2nd pipe
	dp2=open("pipe2",O_WRONLY);
		if(dp2==0) printf("pb ouverture du pipe 2");
	
	//ecriture dans le pipe	
	write(dp2,&ans,strlen(ans));

	//fermeture du pipe
	usleep(500);
	close(dp2);
	
	exit(0);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}



Prog3
int main(int argc, char *argv[])
{
	pid_gp=atoi(argv[1]);
	printf("le pid du gd pere est %d\n",pid_gp);

	unlink("pipe3");
	mkfifo("pipe3",0666);

	signal(SIGUSR2,modif);

	for(;;)
	{
		pause();
	}

	exit(0);
}

void modif(int sig)
{
	int dp2,re,dp3;
	char ans[20];
	char suite[15]="oui";

	//ouverture du pipe
	dp2=open("pipe2",O_RDONLY);
		if(dp2==0) erreur("pb ouverture du pipe 2");
		
	//lecture
	re=read(dp2,ans,sizeof(ans));
		if(re==0) erreur("pb lecture du pipe");
	printf("le resultat chez 5 est\n");
	printf("egal à %s\n",ans);

	//fermeture
	usleep(500);
	close (dp2);

	//modification du message	
	int i=0;
	while(ans[i]!='\0')
		i++;	

	int j=0;
	while(suite[j]!='\0')
	{
		ans[i+j]=suite[j];
		j++;
	}
	strcpy(&ans[i+j],"\0");

	
	//envoie du signal pour dire d'ouvrir l'autre cote du pipe
	kill(pid_gp,SIGUSR1);

	//ouverture du pipe pour parler a 1
	dp3=open("pipe3",O_WRONLY);
		if(dp3==0) erreur("pb ouverture du pipe 3");	
	
	//ecriture dans le pipe
	write(dp3,&ans,strlen(ans));

	usleep(500);
	close(dp3);
}

void erreur(char *mes)
{
	perror(mes);
	exit(-1);
}
0
j'ai appuyé sur ajouter au lieu de prévisualiser...
donc voila la fin de mon message:

Quand j'exécute le programme, le printf("apres sprintf\n") ne s'affiche pas...donc je pense que c'est par là que ca bloque, mais pourquoi ?


Merci
0
Ben oui, c'est normal, rien que du classique !!!
Quant un programme (en C) plante, dans 99% des cas (au moins :-) ), il y a un problème de pointeur !
char* pidpere;
sprintf (pidpere , "%d", getppid());
Il faut bien comprendre que 'pidpere' est un pointeur qui ne pointe sur rien ou plutôt sur n'importe quoi. Il va donc écrire l'entier obtenu par 'getppid()' n'importe où avec les conséquences que tu connais.
Il est donc nécessaire d'initialiser le pointeur par un:
char* pidpere = (char*)malloc(16);
Avec 16, on est peinard pour la longueur de l'entier.
Il faut comprendre qu'un pointeur ne s'utilise pas à la légère, sinon il faut envisager d'utiliser des langages qui ne pose pas ce genre de problème (par exemple Perl ou Python):
- déclaration,
- initialisation ou allocation,
- utilisation,
- destruction.
Ces quatre commandements sont la Bible des pointeurs en C. Il n'y a aucune aide de la part du compilateur; c'est au programmeur de gérer ses pointeurs.
Bon courage.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Merci loupius !

Avec un malloc et un free, ca marche (enfin j'ai d'autres problemes plus loin avec les signaux, mais je vais voir ce que je peux y faire avant de demander...)

Une petite question quand meme: le pointeur il fallait l'initialiser. Est ce que ca aurait marché avec un tableau au lieu d'un pointeur, par exemple avec un char *argv[16] ?
Car un tableau, ca s'initialise ?
0
Oh là là, pin pon pin pon pin pon !!!
Que crois-tu définir avec char *argv[16] ?
Alors, il faut savoir que [] est prioritaire sur *, donc on peut écrire (char*)(argv[16]), c'est à dire un tableau de 10 pointeurs vers des objets de type 'int'... c'est bien ce que tu voulais ?
Dans le cas qui nous intéresse, il suffit d'écrire:
char tableau[16];
sprintf (tableau, "%d", getppid());
Allez encore un p'tit effort et t'auras tout compris ;-)
0
loupius > loupius
21 août 2009 à 01:10
Heu, évidemment, il faut lire un tableau de 16 pointeurs !
0
loupius > loupius
21 août 2009 à 23:43
Qu'est-ce qu'on peut écrire comme bêtises !
Evidemment il fallait lire:
un tableau de 16 pointeurs vers des objets de type 'char'
Ouf, j'y suis enfin arrivé.
Mille excuses.
0
je crois que j'ai compris...
merci loupius pour votre aide !
0