Synchronisation de deux processus

Fermé
unfortic Messages postés 24 Date d'inscription vendredi 1 février 2008 Statut Membre Dernière intervention 16 mai 2012 - 16 mai 2012 à 12:25
unfortic Messages postés 24 Date d'inscription vendredi 1 février 2008 Statut Membre Dernière intervention 16 mai 2012 - 16 mai 2012 à 16:00
Bonjour,

Durant ma révision du cours de programmation système en C sur Linux, je me suis heurté à une problématique plutôt casse tête :-°

Je sais comment synchroniser un père avec un fils, je sais comment synchroniser les fils qu'ils soient structurés en chaîne ou en arbre :D

Mais là je voudrais faire la chose suivante, en ayant deux fils:

-Le fils 1 affiche les entiers impairs de 1 à 100.
-Le fils 2 affiche les entiers pairs de 1 à 100.

L'affichage final devant être dans l'ordre: 1 2 3 4 5... 100. D'ou l'idée d'une synchronisation alternative, mais comment faire? :euh:

J'ai tenté le programme suivant, mais ça s'arrête sur le premier entier 0:

#include<unistd.h>
#include <stdio.h>
#include <signal.h>

void handler1(int sig)
{
if(sig == SIGCONT)
{
raise(SIGCONT);
}
}

void handler2(int sig)
{
if(sig == SIGCONT)
{
raise(SIGCONT);
}
}

int main()
{
int i=-1;

if(fork()==0)
{ signal(SIGCONT,handler1);
while(1)
{
printf("Je suis le fils 1 mon pid est %d\n",getpid());
printf("%d\n",i+1);
pause();
kill(getpid()+1,SIGCONT);
}
}

if(fork()==0)
{
signal(SIGCONT,handler2);
while(1)
{
pause();
printf("Je suis le fils 2 mon pid est %d\n",getpid());
printf("%d\n",i+1);
kill(getpid()-1,SIGCONT);
}
}

}



Merci d'avance :)

3 réponses

scriptiz Messages postés 1424 Date d'inscription dimanche 21 décembre 2008 Statut Membre Dernière intervention 14 septembre 2023 425
16 mai 2012 à 15:20
Bon je me suis amusé à faire un petit programme décrivant donc un père dialoguant avec ces deux fils et s'échangeant des messages sur deux pipes pour dire à chaque fois à qui le tour d'écrire son numéro, voici le source, bien entendu je n'ai pas testé les retours des appels systèmes (si -1 faire un perror()) et il faudrait regrouper le code des deux fils car il est le même, mais bon c'était juste pour faire un petit exemple fonctionnel ^^

#include <unistd.h> 
#include <stdio.h> 
#include <signal.h>
#include <stdlib.h>
#include <string.h>

#define FALSE 0
#define TRUE !FALSE
#define SIZE 80

int main() 
{
	int fd1_a[2]; /* Pipe fils 1 aller */
	int fd1_r[2]; /* Pipe fils 1 retour */
	int fd2_a[2]; /* Pipe fils 2 aller */
	int fd2_r[2]; /* Pipe fils 2 retour */

	int i = 0;
	int n;
	char buffer[SIZE];
	int pid;
	
	strcpy(buffer, "msg");
	
	/* Création des pipes du fils 1 */
	pipe(fd1_a);
	pipe(fd1_r);

	/* Père */
	if(fork()) 
	{
		/* Pipe fils 1 : 1er pour écrire, 2e pour lire */
		close(fd1_a[0]);
		close(fd1_r[1]);
	}
	/* Fils 1 */
	else
	{
		i = 1;
		fd_set rfds1;

		/* 1er pipe pour lire et 2e pour écrire */
		close(fd1_a[1]);
		close(fd1_r[0]);

		while(TRUE) 
		{
			if(i > 20)
			{
				exit(EXIT_SUCCESS);
			}
			
			FD_ZERO(&rfds1);
			FD_SET(fd1_a[0], &rfds1);

			select(fd1_a[0] + 1, &rfds1, NULL, NULL, NULL);
			n = read(fd1_a[0], buffer, SIZE);
			printf("Fils 1 (pid %d) : %d\n", getpid(), i); 
			i += 2;
			write(fd1_r[1], buffer, n);
		} 
	}
	
	/* Création des pipes du fils 2 */
	pipe(fd2_a);
	pipe(fd2_r);
	
	/* Fils 2 */
	if(fork()) 
	{
		/* Pipe fils 2 : 1er pour écrire, 2e pour lire */
		close(fd2_a[0]);
		close(fd2_r[1]);
	}
	else
	{
		i = 2;
		fd_set rfds2;

		/* 1er pipe pour lire et 2e pour écrire */
		close(fd2_a[1]);
		close(fd2_r[0]);

		while(TRUE) 
		{
			if(i > 20)
			{
				exit(EXIT_SUCCESS);
			}
			
			FD_ZERO(&rfds2);
			FD_SET(fd2_a[0], &rfds2);
			
			select(fd2_a[0] + 1, &rfds2, NULL, NULL, NULL);
			n = read(fd2_a[0], buffer, SIZE);
			printf("Fils 2 (pid %d) : %d\n", getpid(), i); 
			i += 2;
			write(fd2_r[1], buffer, n);
		}
	}

	/* Père */
	
	/* Pour amorcer on lance un premier message chez le fils 1 */
	write(fd1_a[1], buffer, SIZE);
	
	while(TRUE)
	{
		int max;
		fd_set rfds;
		FD_ZERO(&rfds);
		
		FD_SET(fd1_r[0], &rfds);
		FD_SET(fd2_r[0], &rfds);
		
		max = fd1_r[0] > fd2_r[0] ? fd1_r[0] : fd2_r[0];
	
		select(max + 1, &rfds, NULL, NULL, NULL);
		
		if(FD_ISSET(fd1_r[0], &rfds))
		{
			/* Si on reçoit un message du fils 1, on envoie au fils 2 */
			n = read(fd1_r[0], buffer, SIZE);
			if(!n) exit(EXIT_SUCCESS);
			write(fd2_a[1], buffer, n);
		}
		else
		{
			/* Si on reçoit un message du fils 2, on envoie au fils 1 */
			n = read(fd2_r[0], buffer, SIZE);
			if(!n) exit(EXIT_SUCCESS);
			write(fd1_a[1], buffer, n);
		}
	}	
}
1
scriptiz Messages postés 1424 Date d'inscription dimanche 21 décembre 2008 Statut Membre Dernière intervention 14 septembre 2023 425
Modifié par scriptiz le 16/05/2012 à 14:37
Je ne sais pas si cela peut t'aider, mais sinon tu peux faire des doubles pipes dont tu ferme à chaque fois un côté pour chacun des fils, et ainsi pouvoir parler entre les fils et le père.

Du coup quand un fils a afficher son numéro, il envoie un bête message sur son pipe retour avec le père.

Quand le père reçoit ce message, il envoie au fils 2 sur son pipe qu'il peut afficher son numéro.

Et ainsi de suite...

En gros 3 select (un père, et un pour chacun des fils) et le tour est joué.

De plus ça peut être le père qui file le numéro à afficher dans son message.

Fin voilà moi je n'ai jamais utiliser les "synchronisation" donc je ferais comme ça.

Bonne chance

PS : tes deux handlers font exactement la même chose, pas besoin d'en écrire un pour chaque fils, ils peuvent appeler la même méthode de façon distincte.
"The most successful method of programming is to begin a program as simply as possible, test it, and then add to the program until it performs the required job." -- PDP8 handbook, Pg 9-64
0
unfortic Messages postés 24 Date d'inscription vendredi 1 février 2008 Statut Membre Dernière intervention 16 mai 2012 3
16 mai 2012 à 16:00
Je commence à réaliser que le problème serait délicat a traiter sans pipes ou sémaphores.

Merci pour ta suggestion.

PS: Si quelqu'un trouve une solution avec signaux ou avec wait/exit, ça serait cool. Merci :)
0