分叉时输出错误的数据

我的c程序有问题。

我正在模拟F1练习。 没有叉子,我有相关的数据。 但是当我分叉得到22个进程时,我得到了无关的数据。

例如:

  • Pilote数字不正确。
  • 不切实际的最佳时间(0分0秒0毫秒)。

这是“制作比赛”的程序(没有分叉):

#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; } 

这是它的输出(正确):

 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 

现在这个程序“让比赛”(现在用叉子)。
只有for(…; j <MAX_PILOTES; …)循环(在main中)发生了变化:

 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 */ 

它的错误输出:

 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) 

最终,显示结果的代码(在另一个.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)" ); } } } 

所以,我的问题是,为什么会发生? 以及如何解决这个问题?

谢谢。

编辑:

我已经建立了一个共享内存,但现在我遇到了两个问题:
– 我不知道何时何地应该分离并删除SM段。
– 所有车辆都有相同的时间(例如:1m45s908ms)。

这是实现的代码(用于共享内存):

 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"); 

这是全新的错误输出:

 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) 

我认为这不是竞争问题。 是吗 ?

好的,所以我不是fork专家,但这是我的诊断

fork时,克隆整个环境。

这意味着无论您在子进程中执行什么操作都不会影响父进程中发生的情况。 在这里,您应该打印子进程中的数据,因为父进程中的pilotes tab完全不受竞争的影响。

您的打印件“错误”,因为您打印的所有值都未初始化。 当您声明表格时,您实际上是打印堆栈中的任何内容。

而且,因为tabPID[j] == 0你正在调用waitpid(0, 0, 0) ,引用man wait(2)

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

由于在子进程中称为IN,您正在等待子进程的子进程的信号,我认为这些信号是不存在的。 你想迁移想要在else调用它

在一个答案中编译最近的评论(对于其他用户):

  • 在分叉程序中访问数据的好方法是设置共享内存(使用shmget )。

  • fork产生的第二个问题是随机生成(在本问题中引发),因为srand仅在父进程中被调用,所有子进程都具有相同的随机种子,因此结果相同。 答案有效:在子进程中调用srand(time(NULL) ^ (getpid()<<16))