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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre du 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
    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
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 838
    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 838
    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
    Membre du 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
    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
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 838
    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 838
    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
    Membre du 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
    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
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 838
    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 838
    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]

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