How to use POSIX semaphores on forked processes in C?

后端 未结 2 1836
失恋的感觉
失恋的感觉 2020-11-27 11:37

I want to fork multiple processes and then use a semaphore on them. Here is what I tried:

sem_init(&sem, 1, 1);   /* semaphore*, pshared, value */
.
.
.
         


        
2条回答
  •  悲哀的现实
    2020-11-27 12:23

    Linux minimal anonymous sem_init + mmap MAP_ANONYMOUS example

    I like this setup as it does not pollute any global namespace as sem_open does.

    The only downside is that MAP_ANONYMOUS is not POSIX, and I don't know any replacement: Anonymous shared memory? shm_open for example takes a global identifier just like sem_open.

    main.c:

    #define _GNU_SOURCE
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char **argv) {
        pid_t pid;
        typedef struct {
            sem_t sem;
            int i;
        } Semint;
    
        Semint *semint;
        size_t size = sizeof(Semint);
        semint = (Semint *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
        assert(semint != MAP_FAILED);
        /* 1: shared across processes
         * 0: initial value, wait locked until one post happens (making it > 0)
         */
        sem_init(&semint->sem, 1, 0);
        semint->i = 0;
        pid = fork();
        assert(pid != -1);
        if (pid == 0) {
            sleep(1);
            semint->i = 1;
            msync(&semint->sem, size, MS_SYNC);
            sem_post(&semint->sem);
            exit(EXIT_SUCCESS);
        }
        if (argc == 1) {
            sem_wait(&semint->sem);
        }
        /* Was modified on the other process. */
        assert(semint->i == 1);
        wait(NULL);
        sem_destroy(&semint->sem);
        assert(munmap(semint, size) != -1);
        return EXIT_SUCCESS;
    }
    

    Compile:

    gcc -g -std=c99 -Wall -Wextra -o main main.c -lpthread
    

    Run with sem_wait:

    ./main
    

    Run without sem_wait:

    ./main 1
    

    Without this synchronization, the assert is very likely to fail, since the child sleeps for one whole second:

    main: main.c:39: main: Assertion `semint->i == 1' failed.
    

    Tested on Ubuntu 18.04. GitHub upstream.

提交回复
热议问题