Как я могу изменить значение позиции массива внутри структуры, которая расположена в общей памяти (mmap) в c? - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь изменить значение позиции массива внутри структуры, которая размещена в разделяемой памяти. У меня есть такая структура:

typedef struct Paths {
     int *path;
     int totalDistance;
     int quantity;
}Path;

И у меня есть этот алгоритм:

void runAlgorithm(int** distances,int nCities, int executionTime, int nProcesses){
int size = nCities+2 * sizeof(int);
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_ANONYMOUS | MAP_SHARED;
PtPath shmem = (PtPath)mmap(NULL, size, protection, visibility, 0, 0);
*shmem = createPath(nCities);
randomPath(shmem);
setPathTotalDistance(shmem, distances);
sem_unlink("job_ready");
sem_unlink("job_done");
sem_t *job_ready = sem_open("job_ready", O_CREAT, 0644, 0);
sem_t *job_done = sem_open("job_done", O_CREAT, 0644, 0);

int *pids = (int*)calloc(nProcesses, sizeof(int));
Path path, shortestPath;

//Workers Processes
for(int i = 0 ; i < nProcesses ; i++){
    pids[i] = fork();
    if(pids[i] == 0){
        shortestPath = createPath(nCities);
        randomPath(&shortestPath); //inicializa caminho aleatorio
        setPathTotalDistance(&shortestPath, distances); //problema aqui 
        while(1){
            sem_wait(job_ready);                
            mutation(&shortestPath, distances);
            if(shortestPath.totalDistance < shmem->totalDistance){
                printPath(shmem);
                printPath(&shortestPath);
                copyPath(&shortestPath, shmem);
            }
            sem_post(job_done);
        }
        exit(0);
    }
}

//Parent Process
int elapsed, terminate = 1;
time_t start = time(NULL), end;
printf("Elapsed time: \n");
while(terminate){
    end = time(NULL);
    elapsed = difftime(end,start);
    printElapsedTime(elapsed);
    if(elapsed >= executionTime)
        terminate = 0;
    else{
        sem_post(job_ready);
        sem_wait(job_done);
    }
}
printPath(shmem);
sem_close(job_ready);
sem_close(job_done);

// Kill worker processes
for (int i=0; i<nProcesses; i++) {
    printf("Killing %d\n", pids[i]);
    kill(pids[i], SIGKILL);
}
}

Это код createPath:

Path createPath(int quantity){
Path newPath;

if(quantity < 0)
    quantity = 0;
newPath.path = (int*)calloc(quantity, sizeof(int));
newPath.quantity = quantity;
newPath.totalDistance = 0;

return newPath;
}

А это код copyPath:

void copyPath(PtPath from, PtPath to){
for(int i = 0 ; i < from->quantity ; i++){
    //printf("posI: %d\n",to->path[i]);
    to->path[i] = from->path[i];
}
to->totalDistance = from->totalDistance;
to->quantity = from->quantity;
}

Так что моя проблема в том, что я пытаюсь скопировать самый короткий путь вразделяет память и ничего не копирует, но копирует totalDistance Что я делаю не так и где?

1 Ответ

0 голосов
/ 06 декабря 2018

Поскольку вы хотите использовать разделяемую память, я рекомендую переписать структуру, поскольку адрес разделяемой памяти может быть изменен при mmap ing (здесь невозможно) или mremap.

ИМХО, всегда лучше использовать смещение внутри разделяемой памяти, чем при использовании указателя и при условии, что адрес не изменится, даже если вы можете быть уверены, что адрес не изменится сейчас.

Итак:

struct Paths
{
    int totalDistance;
    int quantity;
    int path[0];
};

Поскольку path хранится встроенным с Paths непрерывно, нет необходимости в int *path.

Когда вы выделяете память с использованием mmap, size должно быть sizeof(Paths) плюс размер, необходимый для хранения path.

size_t size = sizeof(Paths) + /* Additional size needed for storing path */;
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_ANONYMOUS | MAP_SHARED; 
PtPath shmem = (PtPath) mmap(NULL, size, protection, visibility, -1, 0);

Когда вы обращаетесь к path из Paths, компилятор будет использовать смещение от адреса Paths для доступа к нему, так чтоПока вы держите действительный указатель на разделяемую память с допустимым Paths, вы можете получить к нему доступ, независимо от того, является ли он mmap ed или mremap ed.

Копирование данных из newPath будетпросто:

Path newPath = createPath();
for(int i = 0 ; i < shmem->quantity ; i++)
    shmem->path[i] = newPath.path[i];

Этот метод имеет небольшое преимущество передd используется в вопросе: он не нуждается в дополнительном указателе, который может быть полезен, если вы выделите много Path.

Теперь лучше использовать void initializePath(Path*, int) вместо Path createPath(int):

void initializePath(Path *newPath, int quantity)
{
    if (quantity < 0)
        quantity = 0;
    newPath->quantity = quantity;
    newPath->totalDistance = 0;

    randomPath(shmem);       
    setPathTotalDistance(shmem, distances);
}

И у вас может быть другая функция Path* allocatePath(int) для выделения Path:

Path* allocateSharedPath(int quantity)
{
    size_t size = sizeof(Paths) + quantity * sizeof(int);
    int protection = PROT_READ | PROT_WRITE;
    int visibility = MAP_ANONYMOUS | MAP_SHARED; 

    Path *shmem = (Path*) mmap(NULL, size, protection, visibility, -1, 0);

    if (shmem == NULL)
        /* Handle failure */;

    return shmem;
}

Path* allocatePath(int quantity)
{
    size_t size = sizeof(Paths) + quantity * sizeof(int);

    Path *mem = (Path*) calloc(size, 1);

    if (mem == NULL)
        /* Handle failure */;

    return mem;
}

Кстати, если вы хотите сохранить что-то еще между quantity и pathили вы хотите сохранить path до Paths, вы можете сделать это:

struct Paths
{
    int totalDistance;
    int quantity;
    offset_t offset_to_path;
};

size требуется выделить sizeof(Paths) + /* Additional size needed for storing path */ + /* sizeof whatever else you need to store */.При инициализации инициализируйте offset_to_path до pointer_to_path - pointer_to_Paths, чтобы вы могли получить к нему доступ, добавив offset_to_path к указателю на Paths.

...