分叉时输出错误的数据

时间:2016-12-13 22:59:08

标签: c

我的c程序出了问题。

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

例如:

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

这是"参加比赛的计划" (没有分叉):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <wait.h>

#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 < 0) {
        return 0.0;
    }
    return result;
}


int genTime(const int min, const int max) {
    return ((rand() % (max-min + 1)) + min); // Generate a number between min and max
}

int genRaceEvents(const int max) { // Decide the race events
    return rand() % max; // On génère le nombre entre 0 et max - 1;
}

int compareBest(const void *p1, const void *p2) { // Comparison method for best times
    const struct Pilote *elem1 = p1;
    const struct Pilote *elem2 = p2;

    if (elem1->best < elem2->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 < elem2->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 < stop; i++) {
        tabToFill[i] = tabFiller[i];
    }
}

int run(Pilote *p, char* name) {
    //sem_wait(&semaph);

    /* Instanciation of all the values (except pilote_id) */
    p->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 < MAX_TOURS; i++) { // For every lap

        p->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 < 2) { // Max 2 pit stop
            p->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

现在是#&#34;参加比赛的节目&#34; (现在用叉子)。
只有for(...; j&lt; 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <semaphore.h>

#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)

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

1 个答案:

答案 0 :(得分:3)

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

当您分叉时,您的整个环境都会被克隆。

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

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

此外,由于您tabPID[j] == 0致电waitpid(0, 0, 0) 引用那个人wait(2)

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

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

中调用它

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

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

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