IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Communication père/fils tableau d'entiers.


Sujet :

C

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Communication père/fils tableau d'entiers.
    Bonjour, avant de commencer, je tiens à remercier ceux qui prendront la peine de lire mon message !

    Mon problème est le suivant, je dois faire communiquer un processus père avec ses fils, ces derniers doivent générer deux tableaux et multiplier chaque case entre elles => tab1[i] * tab2[i] pour chaque i.
    le père doit récupérer la somme totale de chaque calcul et l'afficher ( le tout via un tube )

    Mon problème est que je n'arrive pas à récupérer toutes les valeurs calculées par les fils dans le descripteur de lecture via le père...
    Ps : J'ai longuement cherché sur mais sans succès (J'ai sûrement mal cherché ><)

    Voici le programme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<signal.h>
    #include<unistd.h>
    #include <time.h> 
     
    int lerandom(int a, int b){
    	return rand() / (double)(RAND_MAX + 1) * (b-a) + a;
    }
     
    int *generer_tableau(int n){
    	int *tableau=NULL;
    	int i = 0;
    	tableau = malloc(n*sizeof(int));
    	while(i < n){
    		tableau[i]=lerandom(0,10);
    		//printf("case n° %d = %d \n",i,tableau[i]);
    		i++;
    		}
    	return tableau;
    }
     
    int main(int argc, char* argv[]){
    	int tube[2];
    	srand(time(NULL) ^ getpid());
    	// Gérer l'erreur
    	if (pipe(tube)==-1){
    		printf("pipe failed\n");
    		return 1;
    	}
    	int n=atoi(argv[1]);
    	pid_t pid;
    	int i=0,c,somme=0;
    	int *v1 = generer_tableau(n); //premier vecteur
    	int *v2 = generer_tableau(n); //second vecteur
    	for(i=0;i<n;i++){
    		if ((pid=fork())==0){ // Fils
    			printf("Dans le fils, on ferme la lecture\n");
    			// Fermeture de lecture
    			close(tube[0]);
    			c = v1[i]*v2[i];
    			printf("Le fils n°%d a calcule : %d x %d = %d\n",i,v1[i],v2[i],c);
    			write(tube[1],&c,sizeof(int));
    			// Fermeture de l'écriture
    			close(tube[1]);
    			exit(0);
    			}
    		else if (pid==-1){ // erreur
    			error("erreur de creation de tube\n");
    			exit(-1);
    		}
    		else {
    			// Père
    			// On ferme l'écriture
    			// On attend que le processus fils s'exécute 
    			wait(NULL);
    			close(tube[1]);
    			read(tube[0],&c,sizeof(int));
    			somme=c+somme;	
    			printf("Le père calcule la somme et obtient pour le moment : %d\n",somme);
    			close(tube[0]);
    			// On n'oubli pas de fermer la lecture après avoir lu
     
    		}
    	}
    	printf("le père a calculé la somme finale : %d \n",somme);
    	return 0;
    }
    voici ce que ça donne à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ./a.out 2
    Dans le fils, on ferme la lecture
    Le fils n°0 a calcule : -1 x -4 = 4
    Le père calcule la somme et obtient pour le moment : 4
    Dans le fils, on ferme la lecture
    Le fils n°1 a calcule : -9 x -3 = 27
    Le père calcule la somme et obtient pour le moment : 8
    le père a calculé la somme finale : 8

    Cordialement ,
    boblinux

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Bonjour

    C'est un chouette exercice que tu as là. Une question cependant, je n'ai pas très bien compris si tu devais faire un fils différent pour chaque i de ton tableau ou bien si tu devais avoir un père et un fils puis le fils (unique) qui calcule chaque tab1[i] * tab2[i] et qui envoie le tout au père
    Parce que dans ton énoncé j'ai l'impression que c'est la seconde hypothèse mais comme dans ton code tu as écrit le fork() dans la boucle tu auras alors autant de fils que de "i".

    Sinon il y a d'autres soucis avec ton code. En vrac
    • tu génères tes tableaux avant le fork (donc dans l'ancètre commun) alors que tu dis dans l'énoncé que ce sont les fils qui doivent générer les tableaux
    • tu appelles deux fois l'instruction fork() alors qu'il faut ne l'appeler qu'une seule fois mais tester ses deux possibilités pour distinguer le père du fils (là tu crées un fils de plus inutile et inutilisé)
    • le fils écrit un int dans le tube mais le père, lui, récupère 100 octets du tube que tu considères ensuite comme des nombres ce qui n'est pas le cas. Les octets écrits sont les octets de codage d'un int, ce ne sont pas des nombres mis bout à bout. Si par exemple la valeur 512 est codée 0x0100 et que tu traites comme 0x01 puis 0x00 de façon distincte (tes r[i] + somme) tu croiras avoir lu 1 puis 0 !!! C'est ici le plus gros problème de ton code (mais les autres soucis en sont aussi)


    Bon courage - Je sais que tu y arriveras et de toute façon on est tous là.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Communication père/fils tableau d'entiers.
    "tu génères tes tableaux avant le fork (donc dans l'ancètre commun) alors que tu dis dans l'énoncé que ce sont les fils qui doivent générer les tableaux"

    => Autant pour moi, ce n'est pas les fils qui créent le tableau mais bien le programme, il fait cette création une seule fois au début du main (selon l'énoncé). Donc je fais bien de générer les tableaux avant le fork.

    "tu appelles deux fois l'instruction fork() alors qu'il faut ne l'appeler qu'une seule fois mais tester ses deux possibilités pour distinguer le père du fils (là tu crées un fils de plus inutile et inutilisé)"

    => Problème réglé en utilisant une variable pid, qui permet d'éviter de créer le fork inutile (même si ce n'est pas gênant en soit, mais toujours est-il qu'il faut coder le plus proprement possible)

    "le fils écrit un int dans le tube mais le père, lui, récupère 100 octets du tube que tu considères ensuite comme des nombres ce qui n'est pas le cas. Les octets écrits sont les octets de codage d'un int, ce ne sont pas des nombres mis bout à bout. Si par exemple la valeur 512 est codée 0x0100 et que tu traites comme 0x01 puis 0x00 de façon distincte (tes r[i] + somme) tu croiras avoir lu 1 puis 0 !!! C'est ici le plus gros problème de ton code (mais les autres soucis en sont aussi)"

    => Tel est mon problème majeur ! je ne vois vraiment pas comment récupérer proprement la suite de résultats stockés par les fils dans le tube.

    Merci pour la réponse éclairante !

    Je pense à régler les "petits" problèmes rencontrés en éspérant tout de même trouver comment régler le problème majeur, à savoir récupérer la suite d'octets contenant les résultats calculés par les fils.

    ps : Voici mon énoncé, ça peut peut-être aider ceux qui voudraient m'aider pour qu'ils puissent comprendre correctement mes objectifs :
    Soient x et y deux vecteurs de longueur n composés d'entiers, on appelle produit scalaire de x et y l'entier défini par la somme des composantes xiyi des vecteurs.
    Il s'agit dans cet exercice d'écrire le programme scal qui calcule cette quantité en respectant les contraintes suivantes:

    - la valeur de n est un paramètre du programme,
    - le processus scal engendre aléatoirement deux tableaux v1 et v2 de taille n composés d'entiers strictement inférieurs à 10 et les affiche (vous veillerez qu'à chaque nouvelle exécution du programme deux nouveaux tableaux soient engendrés),
    -le processus engendre n fils qui doivent s'éxécuter en parallèle, le fils numéro i calcule la valeur v1[i] x v2[i] et renvoie le résultat à son père,
    -chaque fils affiche un message indiquant le calcul effectué (respectez la syntaxe donnée dans l'exemple),
    -le père calcule la somme de tous les résultats renvoyés,
    -les instructions else et switch ne sont pas utilisées dans le programme, l'instruction if n'est utilisée qu'une seule fois.

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par boblinux Voir le message
    => Tel est mon problème majeur ! je ne vois vraiment pas comment récupérer proprement la suite de résultats stockés par les fils dans le tube.
    Tel le fils l'a écrit, tel le père doit le récupérer
    fils: write(tube[1], &c, sizeof(int))...
    père: read(tube[0], &c, sizeof(int)...
    Hé oui, le fils écrit 2 octets, le père en lit 2. Et comme c'est FIFO, les octets arrivent dans le même sens qu'à l'origine et ton nombre est automatiquement reconstitué.
    Et j'ai mis la même variable "c" pour le père et le fils puisque les deux processus étant totalement indépendants (tout en ayant tous deux accès à la variable "c" créée dans l'ancètre), il n'y aura aucune collision

    Citation Envoyé par boblinux Voir le message
    -les instructions else et switch ne sont pas utilisées dans le programme, l'instruction if n'est utilisée qu'une seule fois.
    Bigre, précis l'énoncé !!!
    Perso j'aime bien mettre un switch pour le fork puisque je gère aussi le cas où fork() échoue (il renvoie -1).
    Toutefois, en écrivant ton corps principal ainsi
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if (fork() == 0)
    {
        // Fils
        ...
    }
    else
    {
        // Père (ou erreur éventuelle qu'on peut aussi vérifier...)
        ...
    }
    Non seulement on met un "else" qui (semble-t-il) n'est pas autorisé mais qui est quand-même plus correct et en plus on n'a pas besoin de variable "pid" (au fait, très très bon choix de nom , j'en ai tant vu sur ce forum qui appellent leur variable "x" ou "y" ou "d" que lire un tel post est très reposant )

    Ceci dit (je viens juste de le voir), tu as écrit if (pid=fork() == 0)...
    Attention au priorités des opérateurs !!! Le "==" étant prioritaire, ta variable pid ne récupèrera pas le pid du fils mais le résultat de la comparaison. Autant dans ton return (rand()%(b-a))+a tu as mis des parenthèses pour rien, autant là tu aurais dû en mettre pour quelque chose...

    Autre amélioration: ton srand(time(NULL)) (qui sert à initialiser l'aléatoire) doit être dans le main et non dans la génération du tableau. Ce n'est pas que ça soit génant mais comme le rand() part de cette initialisation pour générer une suite de nombre aléatoires et te renvoyer à chaque appel le nombre suivant de la suite, une seule initialisation suffit. Par ailleurs si vraiment tu veux un aléatoire plus uniformisé, remplace return (rand()%(b-a))+a (avec ses fameuses parenthèses inutiles) par return rand() / (double)(RAND_MAX + 1) * (b-a) + a. En effet, au lieu de partir sur un modulo (qui restreint les possibilités) tu commences par diviser par la plage des valeurs aléatoires possibles ce qui te donne un nombre floattant entre 0 et 1. Puis en multipliant par la plage des valeurs autorisées, ça te donne le nombre voulu mais tiré d'un état initial plus uniformément réparti...

    Et enfin, tu sembles travailler (ou au moins connaitre) Linux, si ton code est appelé par plusieurs instances différentes au même instant, ils auront tous le même résultat. Pour éviter ce soucis, remplace srand(time(NULL)) par srand(time(NULL) ^ getpid()). Ca fait un mix entre les bits à 1 de l'heure système et ceux du pid courant dans la graine de l'aléatoire. Et si vraiment tu veux une initialisation encore plus fine, tu as un champ "microsecondes" dispo dans la structure remplie par la fonction gettimeofday(). Quand tu expliqueras ça à ton prof il en restera sur le luc
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Communication père/fils tableau d'entiers.
    Re, Encore merci pour ces conseils précieux, cette gentillesse et ce temps pris sur soit pour répondre à la maladresse d'un petit débutant en c...

    J'ai appliqué et modifié mon programme initial (en fait je modifie le premier message au fur et à mesure pour éviter de flooder sur le forum) en fonction des conseils prodigués sur le fil (et cela a amélioré quelque peu mon programme)

    Mais si on jette un coup d’œil à l'exécution, on se rend vite compte que le père ne fait la somme que sur le premier résultat calculé par le fils et ignore tous les autres... pour une raison qui m'est inconnue.
    En fait j'ai envoyé un mail à un de mes professeurs pour des éclaircissements, après quelques conseils très vague, il m'a conseillé de me renseigner sur l'utilisation des tubes...sans vraie solution (peut-être est-ce plus pédagogique?)

    Bref, mon problème réside dans le fait que je n'arrive pas à récupérer entièrement
    tous les résultats des fils pour en faire la somme, mon programme ne fait la somme n fois que sur le premier résultat envoyé par les fils...

    Voilou, Merci en tout cas pour ces aides précieuses, cela m'a fait avancer dans mon programme, mais mon problème majeur subsiste toujours.
    Je n'abandonnerai pas ! et continue mes recherches pour résoudre ce médiocre problème !

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par boblinux Voir le message
    Mais si on jette un coup d’œil à l'exécution, on se rend vite compte que le père ne fait la somme que sur le premier résultat calculé par le fils et ignore tous les autres... pour une raison qui m'est inconnue.
    Tu devrais poster ton code...

    Citation Envoyé par boblinux Voir le message
    En fait j'ai envoyé un mail à un de mes professeurs pour des éclaircissements, après quelques conseils très vague, il m'a conseillé de me renseigner sur l'utilisation des tubes...sans vraie solution (peut-être est-ce plus pédagogique?)
    Ben plutôt il ne sait pas (ceci dit, en l'état de ce que tu nous dit, moi non plus)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Communication père/fils tableau d'entiers.
    Mon code est posté dans mon premier message, en fait je le modifie au fur et à mesure que mes investigations avancent.
    Tu peux y jeter un coup d'oeil en re-lisant mon poste de départ
    J'y ai même l'exécution du programme pour y voir plus clair !
    Sur ce, mes investigations continuent !

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Non non non, il y a eu trop de modifs depuis !!! Si tu veux qu'on t'aide ne nous dis pas de reprendre le tout premier code avec toutes ses erreurs et d'essayer de deviner quelles ont été tes améliorations pour arriver à un code plus fonctionnel mais ayant toujours le soucis que tu décris dans ton avant dernier post !!! Parce que si moi je le corrige ce code, il sera 100% fonctionnel !!!

    Il nous faut ton dernier code pour qu'on t'indique où tu as commis une erreur... et même s'il fonctionne, pour qu'on te donne des conseils d'amélioration/optimisation...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Communication père/fils
    Il y a un mal-entendu en fait, mon dernier code est mon PREMIER code, en effet, sur ce forum, il y a la possibilité de modifier ses messages, donc le code du premier post est en fait mon dernier code avec toutes les mises à jour dessus.
    Donc il n'y a rien à deviner je te rassure, et désolé si c'est moi qui n'ai pas été assez clair sur ce point.
    Donc mon dernier code est dans mon PREMIER POST, si tu regardes tu verras que tu retrouveras dessus les améliorations que tu m'as proposé

    Cordialement,
    Boblinuxz

    PS : Mon problème n'est toujours pas réglé.

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par boblinux Voir le message
    PS : Mon problème n'est toujours pas réglé.
    Chez-moi si !!!

    Déjà je vais te montrer mes lignes de debug: tu verras qu'elles sont plus pertinentes que les tiennes...

    dans le fils: printf("Le fils n°%d (%d) a calcule : %d x %d = %d\n", i, getpid(), v1[i], v2[i], c);...
    dans le père: printf("Le père de %d récupère %d et calcule la somme : %d\n", pid, c, somme);...
    Donc tu vois, déjà en utilisant getpid() et la variable pid j'ai pu voir que les processus qui communiquaient étaient les bons... et en intégrant dans le père la valeur lue du pipe, c'est là que j'ai compris. Je te laisse chercher tout seul, j'espère que tu comprendras aussi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~/tmp$ ./essai 5
    tableau généré: 2, 3, 4, 9, 2, 
    tableau généré: 9, 3, 2, 6, 5, 
    Le fils n°0 (5006) a calcule : 2 x 9 = 18
    Le père de 5006 récupère 18 et calcule la somme : 18
    Le fils n°1 (5007) a calcule : 3 x 3 = 9
    Le père de 5007 récupère 9 et calcule la somme : 27
    Le fils n°2 (5008) a calcule : 4 x 2 = 8
    Le père de 5008 récupère 8 et calcule la somme : 35
    Le fils n°3 (5009) a calcule : 9 x 6 = 54
    Le père de 5009 récupère 54 et calcule la somme : 89
    Le fils n°4 (5010) a calcule : 2 x 5 = 10
    Le père de 5010 récupère 10 et calcule la somme : 99
    le père a calculé la somme finale : 99
    PS: chez-moi, la ligne rand() / (double)(RAND_MAX + 1) * (b-a) + a m'a renvoyé un warning. C'est à cause du RAND_MAX + 1 calculé avant d'être casté et qui dépasse la taille d'un int. J'ai réglé le soucis en écrivant rand() / ((double)RAND_MAX + 1) * (b-a) + a (subtile différence )
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut re
    Merci pour ces conseils mais j'ai vraiment du mal là... au passage j'ai des valeurs totalement abhérentes ...

    Je ne vois vraiment pas comment régler le problème, déjà à cause de ces valeurs abhérrentes (en effet le père devance les calculs !), elles me bloquent pour la suite !
    Pourquoi est-ce que le père devance les fils dans les calculs? la fonction wait(NULL) ne permet d'elle pas d'attendre que le fils ait fini son exécution avant que le père puisse s'exécuter ??
    Pourquoi est-ce ma fonction de génération de tableau aléatoire ne prend plus en compte les valeurs maximales et minimales? pourtant j'ai bien précisé les valeurs 0 et 10..

    J'ai du mal là

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<signal.h>
    #include<unistd.h>
    #include <time.h> 
     
    int lerandom(int a, int b){
    	 rand() / ((double)RAND_MAX + 1) * (b-a) + a;
    }
     
    int *generer_tableau(int n){
    	int *tableau=NULL;
    	int i = 0;
    	tableau = malloc(n*sizeof(int));
    	while(i < n){
    		tableau[i]=lerandom(0,10);
    		//printf("case n° %d = %d \n",i,tableau[i]);
    		i++;
    		}
    	return tableau;
    }
     
    int main(int argc, char* argv[]){
    	int tube[2];
    	srand(time(NULL) ^ getpid());
    	// Gérer l'erreur
    	if (pipe(tube)==-1){
    		printf("pipe failed\n");
    		return 1;
    	}
    	int n=atoi(argv[1]);
    	pid_t pid;
    	int i=0,c,somme=0;
    	int *v1 = generer_tableau(n); //premier vecteur
    	int *v2 = generer_tableau(n); //second vecteur
    	for(i=0;i<n;i++){
    		if ((pid=fork())==0){ // Fils
    			printf("Dans le fils, on ferme la lecture\n");
    			// Fermeture de lecture
    			close(tube[0]);
    			c = v1[i]*v2[i];
    			printf("Le fils n°%d (%d) a calcule : %d x %d = %d\n", i, getpid(), v1[i], v2[i], c);
    			write(tube[1],&c,sizeof(int));
    			// Fermeture de l'écriture
    			close(tube[1]);
    			exit(0);
    			}
    		else if (pid==-1){ // erreur
    			error("erreur de creation de tube\n");
    			exit(-1);
    		}
    		else {
    			// Père
    			// On ferme l'écriture
    			// On attend que le processus fils s'exécute 
    			wait(NULL);
    			close(tube[1]);
    			read(tube[0],&c,sizeof(int));
    			somme=c+somme;	
    			printf("Le père de %d récupère %d et calcule la somme : %d\n", pid, c, somme);
    			close(tube[0]);
    			// On n'oubli pas de fermer la lecture après avoir lu
     
    		}
    	}
    	printf("le père a calculé la somme finale : %d \n",somme);
    	return 0;
    }
    et l'exécution

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    ./a.out 3
    ./a.out 3
    case0 = 2034645808 
    case1 = 1167021034 
    case2 = 1191981694 
    case0 = 21380438 
    case1 = 2049069827 
    case2 = 1181216686 
    Dans le fils, on ferme la lecture
    Le fils n°0 (2988) a calcule : 2034645808 x 21380438 = -657305056
    Le père de 2988 récupère -657305056 et calcule la somme : -657305056
    Le père de 2989 récupère -657305056 et calcule la somme : -1314610112
    Dans le fils, on ferme la lecture
    Le fils n°1 (2989) a calcule : 1167021034 x 2049069827 = -235480642
    Le père de 2990 récupère -657305056 et calcule la somme : -1971915168
    Dans le fils, on ferme la lecture
    Le fils n°2 (2990) a calcule : 1191981694 x 1181216686 = 1914696612
    le père a calculé la somme finale : -1971915168
    En tout cas merci de patienter avec moi et de prendre tout ce temps ! je t'en suis réellement reconnaissant !

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par boblinux Voir le message
    Je ne vois vraiment pas comment régler le problème, déjà à cause de ces valeurs abhérrentes (en effet le père devance les calculs !), elles me bloquent pour la suite !
    Pour les valeurs aberrantes, essaye d'utiliser l'instruction return dans ta fonction lerandom(). Elle fait des miracles quand il s'agit de renvoyer des trucs...

    Pour ton problème de lecture du père, indice: tu as "n" fils mais tu n'as qu'un seul père. Si lui-aussi il fait "n" fois certaines opérations qui ne devraient être faites qu'une seule fois, alors ça ne peut pas fonctionner. Mais sinon je t'assure que ton père ne devance pas la lecture. Ce que tu vois dans ton log c'est à cause de cette simple erreur. De mon coté j'ai repris ton code, l'ai rectifiée (juste elle) et il foncitonne nickel !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Points : 4
    Points
    4
    Par défaut RE
    Re, après m'être un peu plus penché sur le fonction des tubes en C, j'ai fini par comprendre plusieurs choses, parmis celles qui m'ont été utile : il n'y a pas d'écrasement des les tubes, mais les valeurs sont stockées les unes à la suite des autres... Donc pour les lire, il suffit de les lire via une boucle un par un.

    J'avais juste quelques problèmes concernant les fermetures des tubes à bon escient.

    Je poste donc mon code (en open source hein ) , et encore merci à tous ceux qui m'ont aidé !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<signal.h>
    #include<unistd.h>
    #include <time.h> 
     
    int lerandom(int a, int b){
    	return rand() / ((double)RAND_MAX + 1) * (b-a) + a;
    }
     
    int *generer_tableau(int n){
    	int *tableau=NULL;
    	int i = 0;
    	tableau = malloc(n*sizeof(int));
    	while(i < n){
    		tableau[i]=lerandom(0,10);
    		printf("case n° %d = %d \n",i,tableau[i]);
    		i++;
    		}
    	return tableau;
    }
     
    int main(int argc, char* argv[]){
    	int tube[2];
    	srand(time(NULL) ^ getpid());
    	// Gérer l'erreur
    	if (pipe(tube)==-1){
    		printf("pipe failed\n");
    		return 1;
    	}
    	int n=atoi(argv[1]);
    	pid_t pid;
    	int i=0,c,somme=0;
    	int *v1 = generer_tableau(n); //premier vecteur
    	int *v2 = generer_tableau(n); //second vecteur
    	for(i=0;i<n;i++){
    		if ((pid=fork())==0){ // Fils
    			printf("Dans le fils, on ferme la lecture\n");
    			// Fermeture de lecture
    			close(tube[0]);
    			c = v1[i]*v2[i];
    			printf("Le fils n°%d (%d) a calcule : %d x %d = %d\n", i, getpid(), v1[i], v2[i], c);
    			write(tube[1],&c,sizeof(int));
    			// Fermeture de l'écriture
    			close(tube[1]);
    			exit(0);
    			}
    		if (pid==-1){ // erreur
    			error("erreur de creation de tube\n");
    			exit(-1);
    		}
    		}
    	// Père
    	// On ferme l'écriture
    	close(tube[1]);
    	for (i=0;i<n;i++){
    		// Read attend que le processus fils écrive avant de pouvoir lire
    		read(tube[0],&c,sizeof(int));
    		somme=c+somme;	
    		printf("Le père de %d récupère %d et calcule la somme : %d\n", pid, c, somme);
    	}
    	close(tube[0]);
    	// On n'oubli pas de fermer la lecture après avoir lu quand on n'en a plus besoin
    	printf("le père a calculé la somme finale : %d \n",somme);
    	return 0;
    }
    ET voilà une exécution pour des tableau de taille 2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    ./a.out 3
    case0 = 5 
    case1 = 4 
    case2 = 1 
    case0 = 3 
    case1 = 9 
    case2 = 5 
    Dans le fils, on ferme la lecture
    Le fils n°1 (6700) a calcule : 4 x 9 = 36
    Le père de 6701 récupère 36 et calcule la somme : 36
    Dans le fils, on ferme la lecture
    Dans le fils, on ferme la lecture
    Le fils n°2 (6701) a calcule : 1 x 5 = 5
    Le père de 6701 récupère 5 et calcule la somme : 41
    Le fils n°0 (6699) a calcule : 5 x 3 = 15
    Le père de 6701 récupère 15 et calcule la somme : 56
    le père a calculé la somme finale : 56

  14. #14
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Exactement - C'était surtout tes close() dans la boucle du père qui empêchaient ensuite toute autre lecture. Je m'en suis rendu compte quand j'ai vu que les valeurs lues étaient toutes égales à la première. C'est parce que les read() suivants ne lisaient plus rien que la variable "c" restait inchangée.

    De mon coté j'avais écrit le code ainsi

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <unistd.h>
    #include <time.h> 
     
    int lerandom(int a, int b){
    	return rand() / ((double)RAND_MAX + 1) * (b-a) + a;
    }
     
    int *generer_tableau(int n){
    	int *tableau=NULL;
    	int i = 0;
    	tableau = malloc(n*sizeof(int));
    	while(i < n){
    		tableau[i]=lerandom(0,10);
    		//printf("case n° %d = %d \n",i,tableau[i]);
    		i++;
    	}
    	return tableau;
    }
     
    void affiche(int *v, int n)
    {
    	int i;
    	fputs("tableau généré: ", stdout);
    	for (i=0; i < n; i++)
    		printf("%d, ", v[i]);
    	fputc('\n', stdout);
    }
     
    int main(int argc, char* argv[]){
    	int tube[2];
    	srand(time(NULL) ^ getpid());
    	// Gérer l'erreur
    	if (pipe(tube)==-1){
    		printf("pipe failed\n");
    		return 1;
    	}
    	int n=atoi(argv[1]);
    	pid_t pid;
    	int i=0,c,somme=0;
    	int *v1 = generer_tableau(n); //premier vecteur
    	int *v2 = generer_tableau(n); //second vecteur
    	affiche(v1, n);
    	affiche(v2, n);
    	for(i=0;i<n;i++){
    		if ((pid=fork())==0){ // Fils
    			// Fermeture de lecture
    			close(tube[0]);
    			c = v1[i]*v2[i];
    			printf("Le fils n°%d (%d) a calcule : %d x %d = %d\n", i, getpid(), v1[i], v2[i], c);
    			write(tube[1],&c,sizeof(int));
    			// Fermeture de l'écriture
    			close(tube[1]);
    			exit(0);
    		}
    		else {
    			// Père
    			// On attend que le processus fils s'exécute 
    			wait(NULL);
    			read(tube[0],&c,sizeof(int));
    			somme=c+somme;	
    			printf("Le père de %d récupère %d et calcule la somme : %d\n", pid, c, somme);
     
    		}
    	}
    	close(tube[1]);
    	close(tube[0]);
    	// On n'oubli pas de fermer la lecture après avoir lu
    	printf("le père a calculé la somme finale : %d \n",somme);
    	return 0;
    }

    Je profite ainsi de la boucle initiale et garantis aussi que les valeurs reçues seront dans l'ordre de leurs création. En effet, dans mon code, le père attend chaque fils immédiatement à sa création puis va lire ce qu'il a écrit. Ainsi la donnée du fils n° 1 est lue avant que le fils n° 2 soit créé. Toi, tu commences par créer les "n" fils puis seulement ensuite, tu vas lire ce qu'ils ont écrit. Mais rien ne te garanti que le fils n°1 aura écrit son calcul avant le fils n° 2 (même si c'est ce qu'il se passe dans 99% des cas). Dans ton TP ça n'a pas d'importance (l'addition est commutative) mais dans d'autres cas ça peut le devenir.

    Quelques conseils annexes: ne mets pas trop de printf(). Tes infos comme quoi le fils ferme le tube on s'en fout et elles gênent plus qu'autre chose. Si ça merde sur un point, alors tu affiches juste le point qui merde et rien d'autre. En revanche afficher les valeurs initiales (comme je l'ai fait) aurait pu être utile (elles m'ont permis de vérifier l'ensemble). Tu peux aussi ensuite commencer à programmer le cas où le write() du fils échoue ce qui fera alors échouer le read() du père ou alors faire un père un peu plus "générique" ne sachant pas à l'avance combien il y aura de valeurs à lire et devant alors boucler tant que read() réussi.

    Et sinon effectivement un tube c'est comme un vrai tube: on peut rentrer plein de trucs à la suite (et je suis monté jusqu'à plusieurs Mo), tout ce qu'on entre en ressort de l'autre coté. Et en plus tout processus utilisant un coté du tube reste bloqué tant que l'autre coté n'est pas lui-aussi utilisé ce qui offre de façon native un outil de synchro pour protéger des ressources à accès unique (comme par exemple une imprimante)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Gtk et communication père fils
    Par troumad dans le forum GTK+ avec C & C++
    Réponses: 9
    Dernier message: 22/04/2011, 22h04
  2. Mauvaise communication père/fils signaux
    Par Shargat dans le forum Débuter
    Réponses: 4
    Dernier message: 14/03/2010, 12h14
  3. Réponses: 2
    Dernier message: 03/10/2005, 22h16
  4. Réponses: 6
    Dernier message: 23/05/2005, 10h47
  5. [MFC] multithread, communication père<->fils
    Par Joeleclems dans le forum MFC
    Réponses: 19
    Dernier message: 19/05/2005, 10h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo