Salida de datos incorrecta al forking

Tengo un problema con mi progtwig c

Estoy simulando una práctica de F1. Sin tenedor, tengo datos relevantes. Pero cuando bifurco para obtener 22 procesos, obtengo datos irrelevantes.

Por ejemplo:

  • Los números de pilote son incorrectos.
  • Mejores tiempos poco realistas (0min 0sec 0ms).

Aquí está el progtwig que “hace la carrera” (sin el tenedor):

#include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include "CourseF1.h" #include "ResultCourse.h" #define MAX_PILOTES 22 #define MAX_TOURS 44 //sem_t semaph; float ranf() { // PRNG pour des floats [0, 1]. float r = rand() / (float) RAND_MAX; return r; } /** * * method based on Box-Muller transformation: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform * **/ float randGaussien(float m, float s) { /* median m, écart-type s */ float x1, x2, w, y1, result; static float y2; static int use_last = 0; if (use_last) /* use the value of the last call */ { y1 = y2; use_last = 0; } else { do { x1 = 2.0 * ranf() - 1.0; x2 = 2.0 * ranf() - 1.0; w = x1 * x1 + x2 * x2; } while ( w >= 1.0 ); w = sqrt( (-2.0 * log( w ) ) / w ); y1 = x1 * w; y2 = x2 * w; use_last = 1; } result = ( m + y1 * s ); if (result best best) return -1; if (elem1->best > elem2->best) return 1; return 0; } int compareTot(const void *p1, const void *p2) { // Comparison method for total time (full race) const struct Pilote *elem1 = p1; const struct Pilote *elem2 = p2; if (elem1->totalTime totalTime) return -1; if (elem1->totalTime > elem2->totalTime) return 1; return 0; } void fillTab(struct Pilote tabToFill[], struct Pilote tabFiller[], const int start, const int stop) { for (int i = start; i s1 = 3 * 60 * 3600 + 1; p->bestS1 = 3 * 60 * 3600 + 1; p->s2 = 3 * 60 * 3600 + 1; p->bestS2 = 3 * 60 * 3600 + 1; p->s3 = 3 * 60 * 3600 + 1; p->bestS3 = 3 * 60 * 3600 + 1; p->best = 3 * 60 * 3600 + 1; p->totalTime = 0; p->isPit = 0; p->hasGivenUp = 0; p->hasGivenUpDuringRace = 0; p->numberOfPits = 0; //printf("START => n° %d\n", p->best); //printf("%d\n", p->totalTime); //pause(); for (int i = 0; i isPit = 0; // Beginning of lap, the pilote does not pit if (!(p->hasGivenUp)) { // If the pilote didn't give up int givingUpEvent = genRaceEvents(500); // Generate number between 1 and 499 //printf("// %d //\n", givingUpEvent); if (givingUpEvent == 14 && strcmp(name, "Race") == 0) { // If the pilote gave up during race //printf("abd ? => %d\n", givingUpEvent); p->best = 3 * 60 * 3600; //p->hasGivenUp = 1; p->hasGivenUpDuringRace = 1; return 0; // Stop le pilote } else if (givingUpEvent == 14) { // If the pilote gave up (But not during race (maybe practices or qualifications) //printf("abd ? => %d\n", givingUpEvent); p->best = 3 * 60 * 3600 + 3; p->hasGivenUp = 1; return 0; // Stop le pilote } } if (p->numberOfPits isPit = genRaceEvents(2); // Generate number between 0 and 1 if (p->isPit) { p->numberOfPits++; if ((strcmp(name, "Practices") == 0)|| (strcmp(name, "Qualifs") == 0)) continue; // Next iteration (= next lap) } } // Otherwise we can do a lap int S1 = 0.275 * (103000 + randGaussien(5000, 2000)); // portion of the lap * Gausse curve (= min time + fun(médian, écart-type)) int S2 = 0.459 * (103000 + randGaussien(5000, 2000)); int S3 = 0.266 * (103000 + randGaussien(5000, 2000)); if ((strcmp(name, "Race") == 0) && (p->isPit)) { // If we are in race and the pilote pit S1 += genTime(20 * 3600, 25 * 3600); // We add between 20 and 25 sec at the sector 1 } p->s1 = S1; // We save S1 time (S1 = Sector 1) p->s2 = S2; // We save S2 time p->s3 = S3; // etc... int lap = S1 + S2 + S3; // Lap time if (p->bestS1 > S1) p->bestS1 = S1; // If it is its best S1 time, we save it if (p->bestS2 > S2) p->bestS2 = S2; // If it is its best S2 if (p->bestS3 > S3) p->bestS3 = S3; // If it is its best S3 if (p->best > lap) p->best = lap; // If it is its best lap time, we save it if ((strcmp(name, "Race") == 0)) { p->totalTime += lap; } } // End of loop //printf("END => n° %d\n", p->best); } int main(int argc, char const *argv[]) { //printf("hello\n"); srand (time(NULL)); // Useful for random number generation printf("========================================\n"); for (int i = 0; i < 22; i++) { printf("Random: %d\n", genRaceEvents(100)); } printf("=========================================\n"); // Variables pour la course int pilotes_numbers[MAX_PILOTES] = {44, 6, 5, 7, 3, 33, 19, 77, 11, 27, 26, 55, 14, 22, 9, 12, 20, 30, 8, 21, 31, 94}; // Array that conain the pilote ids struct Pilote Q2[16]; // Array of pilotes for Q2 struct Pilote Q3[10]; // Array of pilotes for Q3 struct Pilote mainRun[MAX_PILOTES]; // Array of pilotes for the other shows struct Pilote pilotesTab[22]; pid_t tabPID[MAX_PILOTES]; int j; for (j = 0; j < MAX_PILOTES; j++) { /* Loop: 22 pilotes */ pilotesTab[j].pilote_id = pilotes_numbers[j]; // Init the pilote id run(&pilotesTab[j], "Practices"); // Launch the pratices for the current pilote } printf("==================================================== \n"); fillTab(mainRun, pilotesTab, 0, MAX_PILOTES); // Fill the mainRun Array before sorting and showing the results (will be useful for shared memory) showResults(mainRun, MAX_PILOTES, "Practices"); // show the results printf("====================================================\n"); return 0; } 

Aquí está su salida (correcta):

 1: voiture n°26: (1m44s239ms) 2: voiture n°11: (1m44s503ms) 3: voiture n°33: (1m44s587ms) 4: voiture n°55: (1m44s672ms) 5: voiture n°20: (1m44s720ms) 6: voiture n°12: (1m44s864ms) 7: voiture n°7: (1m45s87ms) 8: voiture n°77: (1m45s136ms) 9: voiture n°8: (1m45s257ms) 10: voiture n°21: (1m45s383ms) 11: voiture n°14: (1m45s553ms) 12: voiture n°94: (1m45s555ms) 13: voiture n°27: (1m45s702ms) 14: voiture n°30: (1m45s731ms) 15: voiture n°9: (1m45s771ms) 16: voiture n°31: (1m45s792ms) 17: voiture n°3: (1m45s835ms) 18: voiture n°5: (1m45s862ms) 19: voiture n°22: (1m45s907ms) 20: voiture n°44: (1m46s212ms) 21: voiture n°6: (1m46s390ms) 22: voiture n°19: Abandon 

Y ahora el progtwig que “hace la carrera” (con el tenedor ahora).
Solo el bucle for (…; j <MAX_PILOTES; …) (en main) ha cambiado:

 pid_t tabPID[MAX_PILOTES]; int j; for (j = 0; j < MAX_PILOTES; j++) { /* Creation of 22 processes */ tabPID[j] = fork(); if (tabPID[j] == -1) { // Error printf("Erreur lors du fork()\n"); return 0; } if (tabPID[j] == 0) { // Fils pilotesTab[j].pilote_id = pilotes_numbers[j]; // Init pilote id //printf("PILOTE ID: %d\n", pilotesTab[j].pilote_id); // OK //waitpid(tabPID[j], NULL, 0); run(&pilotesTab[j], "Practices"); exit(0); } else { /* Nothing */ } } /* End of the 22 processes */ 

Y su salida de buggy:

 1: voiture n°1: Abandon 2: voiture n°32765: (0m0s0ms) 3: voiture n°32593: Abandon 4: voiture n°888005824: Abandon 5: voiture n°32593: Abandon 6: voiture n°1700966438: Abandon 7: voiture n°4196464: Abandon 8: voiture n°0: (0m0s0ms) 9: voiture n°878665720: Abandon 10: voiture n°16220219: Abandon 11: voiture n°885803424: Abandon 12: voiture n°885789819: Abandon 13: voiture n°46: Abandon 14: voiture n°887994784: (0m32s765ms) 15: voiture n°0: Abandon 16: voiture n°32593: Abandon 17: voiture n°32593: Abandon 18: voiture n°0: Abandon 19: voiture n°0: (13193m41s423ms) 20: voiture n°32765: Abandon 21: voiture n°32765: Abandon 22: voiture n°0: (32546m42s655ms) 

Finalmente, el código que muestra los resultados (en otro archivo .c):

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include "CourseF1.h" #include "ResultCourse.h" #define MAX_PILOTES 22 void showResults(struct Pilote tab[], int nbElems, char* name) { if (strcmp(name, "Race") != 0) { qsort(tab, nbElems, sizeof(Pilote), compareTot); for (int k = 0; k < nbElems; k++) { if (tab[k].hasGivenUpDuringRace || tab[k].best == 3 * 60 * 3600 + 3) { printf("%d: voiture n°%d: Abandon\n", k+1, tab[k].pilote_id); continue; } printf( "%d%s%d%s%d%s%d%s%d%s\n" ,k+1, ": voiture n°", tab[k].pilote_id, ": (", tab[k].best/60000, "m", tab[k].best / 1000 % 60, "s", tab[k].best-(tab[k].best/1000)*1000, "ms)" ); } } else { for (int k = 0; k < nbElems; k++) { qsort(tab, nbElems, sizeof(Pilote), compareBest); if (tab[k].hasGivenUpDuringRace || tab[k].best == 3 * 60 * 3600 + 3) { printf("voiture n°%d: Abandon\n", tab[k].pilote_id); continue; } printf( "%d%s%d%s%d%s%d%s%d%s\n" ,k+1, ": voiture n°", tab[k].pilote_id, ": (", tab[k].totalTime/60000,"m", (tab[k].totalTime/1000)%60,"s", tab[k].totalTime-(tab[k].totalTime/1000)*1000,"ms)" ); } } } 

Entonces, mi pregunta es, ¿Por qué sucede? ¿Y cómo arreglar eso?

Gracias.

Editar:

He configurado una memoria compartida pero ahora tengo 2 problemas:
– No sé cuándo y dónde debo separar y quitar el segmento SM.
– Todos los autos tienen el mismo tiempo (ej: 1m45s908ms).

Aquí está el código implementado (para Memoria Compartida):

 struct Pilote *pilotesTab; // pointer to SM. Instead of a simple array of struct as before pid_t tabPID[MAX_PILOTES]; int shmid = 0; key_t key; /** * Set up shared memory */ // Key generation for shared memory key = ftok(argv[0], 123); // argv[O] => nom du programme lancé, ID (char) // Initialisation of shared memory shmid = shmget(key, MAX_PILOTES * sizeof(Pilote), IPC_CREAT | 0644); if (shmid == -1) { printf("Erreur lors de l'allocation de la shared memory."); return 0; } // Attach the shared memory pilotesTab = shmat(shmid, NULL, 0); /** * Fork (The same code than before) */ int j; for (j = 0; j < MAX_PILOTES; j++) { /* Création des 22 processus */ tabPID[j] = fork(); if (tabPID[j] == -1) { // Erreur printf("Erreur lors du fork()\n"); return 0; } if (tabPID[j] == 0) { // Fils pilotesTab[j].pilote_id = pilotes_numbers[j]; // Initialise le numéro du pilote //printf("PILOTE ID: %d\n", pilotesTab[j].pilote_id); // OK run(&pilotesTab[j], "Practices"); exit(0); } else { waitpid(tabPID[j], NULL, 0); //shmdt(pilotesTab); //shmctl(shmid, IPC_RMID, 0); } } /* Fin des 22 processus */ printf("==================================================== \n"); fillTab(mainRun, pilotesTab, 0, MAX_PILOTES); // Fill the tab (mainRun) with the data from the SM (before sorting because we can't sort SM). showResults(mainRun, MAX_PILOTES, "Practices"); printf("====================================================\n"); 

Y aquí está la nueva salida de buggy:

 1: voiture n°44: (1m44s908ms) 2: voiture n°6: (1m44s908ms) 3: voiture n°5: (1m44s908ms) 4: voiture n°7: (1m44s908ms) 5: voiture n°3: (1m44s908ms) 6: voiture n°33: (1m44s908ms) 7: voiture n°19: (1m44s908ms) 8: voiture n°77: (1m44s908ms) 9: voiture n°11: (1m44s908ms) 10: voiture n°27: (1m44s908ms) 11: voiture n°26: (1m44s908ms) 12: voiture n°55: (1m44s908ms) 13: voiture n°14: (1m44s908ms) 14: voiture n°22: (1m44s908ms) 15: voiture n°9: (1m44s908ms) 16: voiture n°12: (1m44s908ms) 17: voiture n°20: (1m44s908ms) 18: voiture n°30: (1m44s908ms) 19: voiture n°8: (1m44s908ms) 20: voiture n°21: (1m44s908ms) 21: voiture n°31: (1m44s908ms) 22: voiture n°94: (1m44s908ms) 

No creo que sea un problema de competencia. Lo es ?

Está bien, no soy un experto en fork , pero aquí está mi diagnóstico

Cuando se bifurca, se clona todo su entorno.

Esto significa que cualquier cosa que haga en el proceso hijo no tiene efecto en lo que sucede en el proceso padre. Aquí, debes imprimir los datos del proceso hijo, porque la pilotes tab en el proceso padre no se ve afectada por la raza.

Su impresión es “defectuosa” porque no se inicializan todos los valores que está imprimiendo. Literalmente estás imprimiendo lo que estaba en la stack cuando declaraste la tabla.

además, como tabPID[j] == 0 está llamando a waitpid(0, 0, 0) que, citando al hombre, wait(2)

 meaning wait for any child process whose process group ID is equal to that of the calling process. 

Como se denomina EN el proceso hijo, está esperando las señales del proceso de los hijos de su hijo, que creo que no existen. Debes llamar a eso en el else

Comstackndo los comentarios recientes en una respuesta (para otros usuarios):

  • Una buena manera de acceder a los datos en un progtwig bifurcado es configurar una memoria compartida (usando shmget ).

  • El segundo problema planteado por una bifurcación es la generación aleatoria (evocada en Esta pregunta ), ya que srand se llama solo en el proceso padre, todos los hijos tienen la misma semilla aleatoria, por lo tanto, los mismos resultados. La respuesta funciona: llamar a srand(time(NULL) ^ (getpid()<<16)) en los procesos secundarios