J'ai du mal à determiner le nombre de processus à créer, je rapelle que le tableau nbprocs contient juste les pid (renvoyés par create_new_child) des fils qui seront crées.
Version imprimable
J'ai du mal à determiner le nombre de processus à créer, je rapelle que le tableau nbprocs contient juste les pid (renvoyés par create_new_child) des fils qui seront crées.
Par rapport au code donné ci-dessus, il y a moyen de simplifier et d'utiliser une seule variable (au lieu de buffer et texte) de type char * qui pointera sur une zone mémoire contenant les x lignes à transmettre au fils.
Cette zone mémoire peut être directement construite dans read_x_lignes.
Je te laisse le soin de faire cette simplification !
Si je construis cette zone mémoire dans read_x_lines, elle sera local, tu ne ense pas?
Je n'ai pas vraiment fais comme tu m'as dis, j'ai déclaré :
dans read_file_and_create_childsCode:
1
2
3 char *paquet; paquet = (char*)malloc( sizeof(char) * TAILLE_LIGNE);
Ensuite je fais pointer paquet sur la premiere ligne de buffer,
puis quand j'apelle creat_new_child, je lui place paquet en argument,Code:
1
2 paquet = *buffer;
mais une fois dans le fils comme on a paquet qui pointe sur la premiere ligne, comme lui dire de parcourir x ligne de buffer? Afin de les afficher puis de les écrire.Code:
1
2 nbprocs[i] = create_new_child(paquet, dstname);
Code:
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 case 0 : { printf(" %d : %s ",getpid(),text); int fd; //FILE *fd; //if((fd=fopen(filename,"a")) == NULL); if((fd=open(filename, O_WRONLY| O_APPEND)) == -1) { perror(" fopen "); exit(1); } //if(fwrite(text,strlen(text), 1, fd) == 0) if(write(fd,text,strlen(text)) == -1) { perror(" write "); exit(1); } //fclose(fd); close(fd); exit(0); } default : { wait((int*)0); return fils; }
Pourquoi allouer de la mémoire à la variable paquet pour ensuite la faire pointer ailleurs ? En faisant cela, la mémoire allouée par malloc devient inaccessible.Code:
1
2
3
4
5
6 char *paquet; paquet = (char*)malloc( sizeof(char) * TAILLE_LIGNE); ... paquet = *buffer;
Il te suffit de faire:
Cependant, si tu transmets paquet (et non pas buffer) à ta fonction, celle-ci n'a aucun moyen d'accéder aux lignes suivantes.Code:
1
2
3char *paquet; paquet = *buffer;
Quelquelchose comme paquet++ n'indique pas la ligne suivante de buffer?
Vu que paquet pointe sur la premiere ligne de buffer.
Je reprends ton code et je te propose:
Ceci ne fonctionnera que si les lignes de tes fichiers font au plus TAILLE_LIGNE-1 caractères.Code:
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define TAILLE_LIGNE 64 // lit x lignes et les place dans le buffer int read_x_lines(FILE *file, char *buffer, int x) { int nb_lignes_lues = 0; int i=0; int len = 0; while((fgets(&buffer[len],TAILLE_LIGNE,file))!= NULL && i<x) { nb_lignes_lues++; i++; len += strlen(&buffer[len]); } return nb_lignes_lues; } // crée un fils en lui transmettant une chaine de caractère qu'il devra afficher et écrire dans le fichier "filename" int create_new_child(char *text, char *filename) { pid_t fils; printf(" Creation du fils \n"); fils = fork(); switch(fils) { case -1 : { perror(" fork "); exit(1); } case 0 : { printf(" %s \n",text); int fd; if((fd=open(filename,O_WRONLY | O_APPEND)) == -1) { perror(" fopen "); exit(1); } if(write(fd,text,strlen(text)) == -1) { perror(" write "); exit(1); } //fclose(fd); close(fd); exit(0); } default : { wait((int*)0); return fils; } } } int *read_file_and_create_childs(char *srcname, char *dstname, int x, int *nbprocs) { int i = 0; char *buffer; buffer = (char *)malloc(x*TAILLE_LIGNE); FILE *file = fopen(srcname,"r"); i = 0; while(i<x) { if (read_x_lines(file, buffer, x) != x) { /* a toi de voir */ } nbprocs[i] = create_new_child(buffer, dstname); i++; } fclose(file); free(buffer); return nbprocs; } int main(int argc, char **argv) // argv[1] = n, argv[2] = fichier_source, argv[3] = fichier_destination { pid_t pid; int n = atoi(argv[1]); int *PID; PID = (int *) malloc(n*sizeof(int *)); PID = read_file_and_create_childs(argv[2], argv[3], n, PID); exit(0); }
Une remarque: es tu sûr que le nombre de processus fils doit être égal au nombre de lignes affichées par chaque fils ?
Par contre il faudrait changer la condition d'arret du while :
x étant la taille des paquets de lignes, adettons que le fichier texte à lire ait n lignes, il faut créer n/x processus si n%x =0 sinon n/x + 1 processus.Code:
1
2
3
4
5
6
7
8
9
10
11 i = 0; while(i<x) { if (read_x_lines(file, buffer, x) != x) { /* a toi de voir */ } nbprocs[i] = create_new_child(buffer, dstname); i++; }
Le probleme comment savoir combien y aura - t-il de ligne dans ce fameux fichier texte?
D'où ma question précédente !
Deux solutions:
- faire une première passe de lecture du fichier pour déterminer le nombre de lignes
- ou: lire tout le fichier en mémoire
En repartant de ton code, voici une implémentation de la deuxième solution:
Code:
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define TAILLE_LIGNE 64 #define NB_LIGNES 32 /* lit le fichier en mémoire */ /* en entrée: buffer est une zone mémoire de *taille_buffer octets */ int charge_en_memoire(FILE *file, char *buffer, int *taille_buffer) { int nblig, len; for(nblig=0,len=0;;) { /* teste si l'on ne déborde pas de buffer */ /* si c'est le cas, réalloue buffer */ if (len+TAILLE_LIGNE>*taille_buffer) { char *tmp = NULL; /* réalloue une zone mémoire plus grande */ /* on aurait pu aussi déterminer la taille du fichier en utilisant stat */ /* ce qui aurait permis d'allouer directement la bonne taille mémoire */ tmp = realloc(buffer,(NB_LIGNES*TAILLE_LIGNE+(*taille_buffer))*sizeof(char)); if (tmp == 0) { /* erreur a gerer */ } buffer = tmp; *taille_buffer += NB_LIGNES*TAILLE_LIGNE; } if (fgets(&buffer[len],TAILLE_LIGNE,file) == NULL) { break; /* en principe, il faudrait tester errno pour déterminer s'il s'agit */ /* d'une erreur ou de la fin de fichier (ou tester feof) */ } len += strlen(&buffer[len]); nblig++; } return nblig; } // crée un fils en lui transmettant une chaine de caractère qu'il devra afficher et écrire dans le fichier "filename" int create_new_child(char *text, char *filename) { pid_t fils; printf(" Creation du fils \n"); fils = fork(); switch(fils) { case -1 : { perror(" fork "); exit(1); } case 0 : { printf(" %s \n",text); int fd; if((fd=open(filename,O_WRONLY | O_APPEND)) == -1) { perror(" fopen "); exit(1); } if(write(fd,text,strlen(text)) == -1) { perror(" write "); exit(1); } close(fd); exit(0); } default : { wait((int*)0); return fils; } } } int *read_file_and_create_childs(char *srcname, char *dstname, int x, int *pids) { int i = 0; char *buffer = NULL; char *buffer_fils = NULL; int taille_buffer; int nbprocs; char *s; int idx, j; taille_buffer = NB_LIGNES*TAILLE_LIGNE; buffer = (char *)malloc(taille_buffer*(sizeof(char)); if (buffer == NULL) { /* à gérer */ } buffer_fils = (char *) malloc(x*TAILLE_LIGNE*sizeof(char)); if (buffer_fils == NULL) { /* à gérer */ } FILE *file = fopen(srcname,"r"); nblig = charge_en_memoire(file, buffer, &taille_buffer); /* calcule le nombre de processus nécessaires */ nbprocs = nblig/x + (nblig%x ? 1 : 0); i = 0; idx = 0; while(i<nbprocs) { /* construit une zone de x lignes à destination du fils */ /* (on pourrait aussi ne pas utiliser un autre buffer en insérant */ /* un '\0' après la (i+x) ème ligne de buffer) */ for (j=0,s=&buffer[idx];s != NULL && j<x;j++) { s = strchr(s,'\n'); if (s != NULL) s++; } if (s != NULL) { int len; len = (int) (s-&buffer[idx]); memcpy(buffer_fils,&buffer[idx],len); buffer_fils[len] = 0; idx += len; } else strcpy(buffer_fils,&buffer[idx]); pids[i] = create_new_child(buffer_fils, dstname); i++; } fclose(file); free(buffer_fils); free(buffer); return pids; } int main(int argc, char **argv) /* argv[1] = n, argv[2] = fichier_source, argv[3] = fichier_destination */ { pid_t pid; int n = atoi(argv[1]); int *PID; PID = (int *) malloc(n*sizeof(int)); PID = read_file_and_create_childs(argv[2], argv[3], n, PID); free(PID); exit(0); }
Juste quelques question.
A quoi correspond len et à quoi dois -je l'initialiser.
Ensuite pourquoi une boucle infinieCode:
1
2 if (len+TAILLE_LIGNE>*taille_buffer)
Code:
1
2 for(nblig=0;;)
len correspond à l'indice du tableau buffer où l'on doit insérer les prochaines données. Il est initialisé à 0 en début de boucle:Citation:
A quoi correspond len et à quoi dois -je l'initialiser.
et évolue à chaque lecture de ligne:Code:for(nblig=0,len=0;;)
Code:len += strlen(&buffer[len]);
On ne sait pas combien de lignes comporte le fichier à lire. L'option choisie est de faire une bloucle infinie et de sortir de cette boucle quand le fgets retournera NULL.Citation:
pourquoi une boucle infinie
J'ai une remarque aussi: c'est carrément stupide de devoir construire (à partir du fichier chargé en mémoire) une zone mémoire contenant exactement les x lignes à transmettre au fils sous prétexte qu'on ne doive pas transmettre le paramètre x au fils. Mais bon, c'est toi qui voit !