Reputation: 535
I want to share semaphore to all process by using shared memory. First, I am mapping object "sem" to shared memory in the parent process. After forking processes, I am doing the same, but with the "sem" in childs process's addres space. It is supposed to work with one semaphore in shared memory by all processes, but it is not working. Something wrong with sharing semaphore. I can't use named semaphore.
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
void doSomething();
void shareSem();
void recieveSem();
sem_t sem;
int main(int argc, char *argv[]) {
shareSem();
sem_init(&sem, 1, 1);
for(int i = 0; i < 1; i++){
int pid = fork();
if(pid == 0)
recieveSem();
};
doSomething();
return 0;
}
void doSomething() {
int i, time;
for (i = 0; i < 3; i++) {
// P operation
if (sem_wait(&sem) == 0) {
// generate random amount of time (< 30 seconds)
time = (int) ((double) rand() / RAND_MAX * 5);
printf("Process %i enters and sleeps for %d seconds...\n", getpid(), time);
sleep(time);
printf("Process %i leaves the critical section\n", getpid());
// V operation
sem_post(&sem);
}
else
printf("Process id: %d :error\n", getpid());
}
}
void shareSem()
{
int fd, status;
fd = shm_open("/swp_es", O_RDWR | O_CREAT, 0777);
if(fd == -1) {
printf("shm_creator1");
}
status = ftruncate(fd, sizeof(sem));
if(status != 0) {
printf("shm_creator2");
}
void *ptr = mmap(&sem, sizeof(sem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(ptr == MAP_FAILED) {
printf("shm_creator3");
}
}
void recieveSem()
{
int fd;
fd = shm_open("/swp_es", O_RDWR, 0777);
if(fd == -1) {
printf("shm_user");
}
void *ptr = mmap(&sem, sizeof(sem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(ptr == MAP_FAILED) {
printf("shm_user");
}
//munmap(buffer, sizeof(buffer));
}
Result is:
Process 4534308 enters and sleeps for 2 seconds...
Process id: 4534309 :error
Process id: 4534309 :error
Process id: 4534309 :error
Process 4534308 leaves the critical section
Process 4534308 enters and sleeps for 0 seconds...
Process 4534308 leaves the critical section
Process 4534308 enters and sleeps for 1 seconds...
Process 4534308 leaves the critical section
Upvotes: 0
Views: 886
Reputation: 181149
You are missing that mmap()
does not necessarily map the shared memory segment to the specific address you give. Moreover, on some systems, there are particular alignment requirements for the address, and mmap()
will fail if the pointer you give does not satisfy those. It is far more portable to pass NULL
as the address, and just let the system choose. Then whatever location the system chooses, put your semaphore there.
Also, you're making it too hard. If you fork()
a child process then it inherits the parent's memory mappings. You don't have to recreate them.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
void doSomething(sem_t *sem);
int main(int argc, char *argv[]) {
int shm_fd = shm_open("/swp_es", O_RDWR | O_CREAT, 0600);
sem_t *sem;
int i;
if (shm_fd == -1) {
printf("Failed to create/open a shared memory object\n");
return 1;
}
if (ftruncate(shm_fd, sizeof(*sem)) != 0) {
printf("Failed to resize the shared memory object\n");
return 1;
}
sem = mmap(NULL, sizeof(*sem), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if(sem == MAP_FAILED) {
printf("Failed to mmap() the shared memory object\n");
return 1;
}
/* It's safe to unlink once the shared memory is mapped */
if (shm_unlink("/swp_es") < 0) {
printf("warning: failed to unlink the shared memory object\n");
}
if (sem_init(sem, 1, 1) != 0) {
printf("Failed to initialize the semaphore\n");
return 1;
}
for(i = 0; i < 1; i++){
int pid = fork();
if (pid < 0) {
printf("Failed to fork()\n");
return 1;
} else if (pid == 0) {
printf("Child %d successfully fork()ed\n", i);
}
};
doSomething(sem);
return 0;
}
void doSomething(sem_t *sem) {
int i;
for (i = 0; i < 3; i++) {
if (sem_wait(sem) == 0) {
int time = (int) (rand() / (RAND_MAX * 5.0));
printf("Process %i enters and sleeps for %d seconds...\n", getpid(), time);
sleep(time);
printf("Process %i leaves the critical section\n", getpid());
sem_post(sem);
}
else {
printf("Process id: %d :error in sem_wait()\n", getpid());
break;
}
}
}
Upvotes: 1