csemaphorefutex

How to find what causes the futex facility to fail?


I am trying to synchronize 5 processes, they have to be created from the same father.

I tried inserting 5 waitpids to wait for the child process to end, but the code never reaches D4 and D5.

#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <sys/wait.h>


void func1(sem_t sem1, sem_t sem2);
void func2(sem_t sem1, sem_t sem2);
void func3(sem_t sem1, sem_t sem2);
void func4(sem_t sem1, sem_t sem2);
void func5(sem_t sem1, sem_t sem2);

int main() {
    sem_t s1;
    sem_t s2;

    sem_init(&s1, 1, -1);
    sem_init(&s2, 1, -1);

    void (*arr[5])(sem_t, sem_t) = {func1, func2, func3, func4, func5};

    int pid;

    for (int i=0; i<5; i++) {
        pid = fork();
        if (pid == 0) {
            arr[i](s1, s2);
            break;
        }
    }

    return 0;
}


void func1(sem_t sem1, sem_t sem2) {
    system("echo D1");
    sem_post(&sem1);
}

void func2(sem_t sem1, sem_t sem2) {
    system("echo D2");
    sem_post(&sem1);
}

void func3(sem_t sem1, sem_t sem2) {
    system("echo D3");
    sem_post(&sem2);
}

void func4(sem_t sem1, sem_t sem2) {
    sem_wait(&sem1);
    system("echo D4");
    sem_post(&sem2);
}

void func5(sem_t sem1, sem_t sem2) {
   sem_wait(&sem2);
    system("echo D5");
}

I expect D4 to be shown after D1 and D2, and D5 to be shown last (D3 in independent from D1,D2,D4). But my code never reaches D4 because the futex facility returns an unexpected error.

Output:

The futex facility returned an unexpected error code.D1
D2
D3

Solution

  • You're passing the semaphores by value, which is incorrect, as the sem_t variable in each function is a copy of the original. (That's why functions such as sem_init(), sem_post(), and sem_wait() all take addresses of the semaphore as an argument.)

    You need to pass the semaphores by address, so each function operates on the original semaphores:

    void func1(sem_t *sem1, sem_t *sem2);
    void func2(sem_t *sem1, sem_t *sem2);
    void func3(sem_t *sem1, sem_t *sem2);
    void func4(sem_t *sem1, sem_t *sem2);
    void func5(sem_t *sem1, sem_t *sem2);
    

    and

    void (*arr[5])(sem_t *, sem_t *) = {func1, func2, func3, func4, func5};
    

    And call the function as:

            arr[i](&s1, &s2);
    

    The functions should then take the form:

    void func1(sem_t *sem1, sem_t *sem2) {
        system("echo D1");
        sem_post(sem1);
    }
    

    Note that the address passed to func1() is passed directly to sem_post().

    Edit:

    As others have noted, you're initializing the semaphores incorrectly. You can't initialize a semaphore to a negative value.

    Proper shared semaphores

    As noted in the comments, the semphores aren't in memory shared between the multiple processes.

    One way to put the semphores in shared memory is to use mmap():

    #include <sys/mman.h>
    
    int main() {
        ...
        // map a 4k page of shared memory (assumes a sem_t is small
        // enough to fit at least two)
        void *sharedMem = mmap( 0, 4 * 1024, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0 );
    
        // use the mmap()'d memory as shared semphores
        sem_t *semArray = ( sem_t * ) sharedMem;
    
        // initialize the semaphores
        sem_init( &( semArray[ 0 ] ), 1, 0 );
        sem_init( &( semArray[ 1 ] ), 1, 0 );
    

    The calling code becomes

        arr[i](&( semArray[ 0 ] ), &( semArray[ 1 ] ));