Search code examples
cstructshared-memorymemcpy

copy of a struct in C


in a project in c I have to copy an array of struct from a sharedMemory

i'm doing :

int status = 0;
pid_t wpid;
f1 *input = (f1*) shmat(shmid,0,0);
while ((wpid = wait(&status)) > 0){
    memcpy(&carList, &input, sizeof(input));
}

f1 is my structure of a car.

but nothing is copied in the carList, but the values are in input from the son Process i think the problem is on this part of the code, i tried multiples others possibilities but i don't find any where else.

I have to use the shared memory to create 20 son and make them generate random times for a race like car.

So i created 20 son that i linked to a entry of an array of they struct, and make them write in it the time they generate.

Then, from time to time, the father copy the array of struct to make a dynamic table of all the time from the cars. I know that using the cpu-scheduler is not the best idea but that's what we have to do in the lecture so we have no choices.

full code but it's a bit long (and i'm french so the notes are in french)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> // bool
#include <unistd.h> //fork
#include <string.h> //strcat
#include <sys/wait.h> //wait
#include <sys/types.h>
#include <sys/shm.h>

#define TURN 3
#define SECTION 3
#define CAR 20
#define KEY 666
#define STANDPOURCENT 10

typedef struct {
    int number;
    int stands;
    bool out;
    int totalTime;

    int circuit[TURN][SECTION];
} f1;

int carListNumber[CAR] = {7, 99, 5, 16, 8, 20, 4, 55, 10, 26, 44, 77, 11, 18, 23, 33, 3, 27, 63, 88};
f1 carList[CAR];
/***********************************************************************************************************************
 *                               fonctions
 **********************************************************************************************************************/

/**
 * renvois un nombre compris entre 40 et 45 secondes pour le
 * clacul du temps des tours de circuits
 * @return integer between 40 and 45
 */
int genSection(){
    int time = 45 - (rand() % 9);
    sleep(time/20);
    return time; // gestion du random et du temps perdu
}

/**
 * génération du temps d'arret au stand
 * @return integer between 2 and 5
 */
int genRandomStand(){
    return  5 - (rand() % 3);
}

/**
 * génération nombre entre 1 et 100
 * @return int between 1 and 100
 */
int genRandom(){
    return 100 - (rand() % 100);
}

/**
 * clear de la console
 */
void clrscr(){
    system("clear");
}

/**
 * affichage du tableau de résultat de tout les tours pour toutes les voitures et sections
 */
void showRun(){
    clrscr();
    for (int turn = 0; turn < TURN; turn++){
        for(int car = 0; car < CAR; car++){
            printf("Voiture %3d || turn : %3d ||S1 : %1d | S2 : %2d | S3 : %2d  || Total Turn : %3d \n",carList[car].number,
                   turn+1,
                   carList[car].circuit[turn][0],
                   carList[car].circuit[turn][1],
                   carList[car].circuit[turn][2],
                   carList[car].circuit[turn][0]+carList[car].circuit[turn][1]+carList[car].circuit[turn][2]);
        }
        printf("---------------------------------------------------------------------------------------------------------------\n");
    }
}

/**
* generation de la liste des structur voitrure sur base de la liste des numero de voitures
* @return void
*/
void init_car_list(int *carListNumber){
    for(int i = 0; i < CAR; i++){
        carList[i].number = carListNumber[i];
        carList[i].stands = 0;
        carList[i].out = false;
        carList[i].totalTime = 0;
        memset(carList[i].circuit, 0, sizeof(carList[i].circuit));
    }
}

/**
 * initalistation de la voiture passé en param
 * @param carNumber
 */
f1 init_car(int carNumber){
    f1 tmp;
    tmp.number = carNumber;
    tmp.stands = 0;
    tmp.out = false;
    tmp.totalTime = 0;
    memset(tmp.circuit, 0, sizeof(tmp.circuit));
    return tmp;
}

/**
 * fonction du code du fils (voiture)
 */
void circuit_son(int shmid,int carPosition){
    int carNumber = carListNumber[carPosition];
    //printf("in son %d : car number %d\n",carPosition,carNumber);
    f1 *output = (f1 *) shmat(shmid, 0, 0);
    printf("Départ de la voiture %d\n",carNumber);
    f1 *currentCar;
    srand(time()+getpid()); // génération du nouveau random pour chaque fils
    //printf("récupération de la strcuct voiture %d \n",carNumber);
    for(int i = 0; i < CAR; i++){
        if(output[i].number == carNumber){
            currentCar = &output[i];
            //printf("Récupération de :: output %d || carNumber %d || current car %d \n",output[i].number,carNumber,currentCar->number);
            break;
        }
    }
    for(int i = 0; i < TURN; i++){ // pour chaque tour
        for(int j = 0; j < SECTION; j++){ // pour chaque section du tour
            currentCar->circuit[i][j] = genSection();
            printf("car %d , %d \n",currentCar->number,currentCar->circuit[i][j]);
        }
        if (genRandom() > STANDPOURCENT || (i == (TURN-1) && currentCar->stands == 0)){ // 50% de s'arreter ou si jamais arrêter pendant la course
            currentCar->circuit[i][SECTION-1] += genRandomStand();
            printf("arret de la voiture %d au stand , temps total de la section 3 : %d \n",currentCar->number,currentCar->circuit[i][SECTION-1]);
            currentCar->stands++;
        }
    }
    exit(EXIT_SUCCESS);
}

/**
 * fonction du père
 * @return
 */
void circuit_father(int shmid){
    int status = 0;
    pid_t wpid;
    // récupération des données de la SM
    f1 *input = (f1*) shmat(shmid,0,0);
    while ((wpid = wait(&status)) > 0){ // temps que un processus est en cours
        memcpy(&carList, &input, sizeof(input));
        printf("input %d %d %d \n",input[4].circuit[1][0],input[4].circuit[1][1],input[4].circuit[1][2]);
        //showRun();
        printf("show run here in father || %d %d %d\n",carList[4].circuit[1][0],carList[4].circuit[1][1],carList[4].circuit[1][2]);
    }
}

/**
 * gestion des tours d essais des voitures
 * @param shmid id de la memoire partagée
 * @return -1 if error else 0
 */
int gen_circuit(int shmid) {
    for (int car = 0; car < CAR; car++) {
        int pid = fork();
        if (pid < 0) {
            perror("error on creation of car");
            printf("\n");
            return -1;
        }
            /* Son */
        else if (pid == 0) {
            circuit_son(shmid,car);
        }
    }
    /* Parent */
    circuit_father(shmid);
    return 0;
}

/**
 * initalisation de la shared memory
 */
void init_mem(shmid){
    f1 *mem = (f1 *) shmat(shmid, 0, 0);
    for(int i = 0; i < CAR; i++){
        mem[i] = init_car(carListNumber[i]);
    }
}

/**
 *
 * @return
 */
int main(){
    // initalisation des voitures
    init_car_list(carListNumber);
    // allocation de la mem partagée
    int shmid = shmget(KEY, (20 * sizeof(f1)),0666 | IPC_CREAT); // 0775 || user = 7 | groupe = 7 | other = 5
    if (shmid == -1){
        perror("ERROR in creation of the Shared Memory");
        printf("\n");
        shmctl(shmid,IPC_RMID,NULL); // suppression de la memoire partagée
        return 1;
    }
    init_mem(shmid);
    // gestion du circuit

    gen_circuit(shmid);
    printf("tout les tours sont terminé \n");
    printf("affichage des Résultats : \n");
    //showRun();

    // fin de la course
    printf("fin des tours \n");
    shmctl(shmid,IPC_RMID,NULL); // suppression de la memoire partagée
    return 0; // fin du programme
}

Solution

  • There are two major problems with the memcpy call you show, and one minor problem:

    1. You pass &input as the source pointer. The problem here is that &input is a pointer to the variable input and not a pointer to the shared memory where input is pointing. That means you copy the pointer and not the data being pointed to. To solve this problem use plain input.

    2. As the size you use sizeof(input), which is the size of the pointer itself, not the size of what it points to. The size you probably want to copy is sizeof carList, which is the size of the destination array (in bytes).

    3. The minor problem is the destination, where you use &carList. This is a pointer to the array, and have the type f1 (*)[20]. What you need is a pointer to the first element of the array, which is &carList[0], or plain carList (which is the same).

    So the call should probably look like

    memcpy(carList, input, sizeof carList);  // Copy from the shared memory into our local array