Stark
Stark

Reputation: 535

Share semaphore to processes

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

Answers (1)

John Bollinger
John Bollinger

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

Related Questions