Поделитесь семафором с процессами

Я хочу поделиться семафором со всеми процессами, используя общую память. Во-первых, я сопоставляю объект «sem» с разделяемой памятью в родительском процессе. После разветвления процессов я делаю то же самое, но с «sem» в адресном пространстве дочернего процесса. Предполагается работа с одним семафором в разделяемой памяти всеми процессами, но он не работает. Что-то не так с совместным использованием семафора. Я не могу использовать именованный семафор.

#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));
}

Результат:

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

person Stark    schedule 04.11.2014    source источник


Ответы (1)


Вы упускаете из виду, что mmap() не обязательно сопоставляет сегмент общей памяти с указанным вами адресом. Кроме того, в некоторых системах существуют особые требования к выравниванию адреса, и mmap() не будет работать, если указанный вами указатель им не соответствует. Гораздо удобнее передать NULL в качестве адреса и просто позволить системе выбрать. Затем, какое бы место ни выбрала система, поместите туда свой семафор.

Кроме того, вы слишком усложняете задачу. Если вы fork() дочерний процесс, то он наследует отображение памяти родителя. Вам не нужно воссоздавать их.

Пример:

#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;
        }
    }
}
person John Bollinger    schedule 04.11.2014