Reputation: 63
I am trying to change the value of a position of an array inside a struct that is allocated in shared memory I have this struct:
typedef struct Paths {
int *path;
int totalDistance;
int quantity;
}Path;
And i have this algorithm:
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);
}
}
This is the code of 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;
}
And this is the copyPath code:
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;
}
So my problem is i'm trying to copy the shortestPath to the shared memory and it copies nothing, but it does copy the totalDistance What am i doing wrong and where?
Upvotes: 1
Views: 83
Reputation: 2748
Since you want to use shared memory, then I recommand you to rewrite the structure since the address of the shared memory can be changed when mmap
ing (not possible here) or mremap
.
IMHO, it is always better to use offset inside shared memory than using pointer and assuming the address won't be changed, even if you can sure the address won't change now.
So:
struct Paths
{
int totalDistance;
int quantity;
int path[0];
};
Since path
is stored inlined with Paths
continuously, there is no need for int *path
.
When you allocate memory using mmap
, the size
should be sizeof(Paths)
plus the size you need for storing 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);
When you accessing path
from Paths
, the compiler will use offset from the address of Paths
to access it, so as long as you hold a valid pointer to a shared memory with valid Paths
, you can access it no matter it is mmap
ed ormremap
ed.
Coping the data from newPath
will be just:
Path newPath = createPath();
for(int i = 0 ; i < shmem->quantity ; i++)
shmem->path[i] = newPath.path[i];
This method has a slight advantage over the method used in the question: it does not need any additional pointer, which might be useful if you allocate a lot of Path
.
Now, it is better to use void initializePath(Path*, int)
instead of 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);
}
And you can have another function Path* allocatePath(int)
to allocate 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;
}
BTW, if you want to store something else between quantity
and path
or you want to store path
before Paths
you can do this:
struct Paths
{
int totalDistance;
int quantity;
offset_t offset_to_path;
};
The size
required to allocate is sizeof(Paths) + /* Additional size needed for storing path */ + /* sizeof whatever else you need to store */
. When initializing, initialize offset_to_path
to pointer_to_path - pointer_to_Paths
so that you can access it by adding offset_to_path
to the pointer to Paths
.
Upvotes: 1