Goutam Bose
Goutam Bose

Reputation: 35

Mutex Shared between processes not working

I'm trying to create a simple shared mutex between processes. The idea is that I will run the same executable twice to create two processes and the first process should create a shared mutex and lock it and go to sleep for some time, meanwhile the other process should find the shared mutex locked and should report the same. For this I've written the below code -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MYMUTEX "/mymutex"

int main(int argc, char* argv[])
{
    pthread_cond_t *cond;
    pthread_mutex_t *mutex;
    int cond_id, mutex_id;
    int mode = S_IRWXU | S_IRWXG;
    /* mutex */
    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR, mode);
    printf("Mutex Id : %d\n", mutex_id);
    if (mutex_id < 0) {
        printf("shm_open failed\n");
        return -1;
    }
    if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
        printf("ftruncate failed\n");
        return -1;
    }
    mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
    if (mutex == MAP_FAILED) {
        printf("mmap failed\n");
        return -1;
    }
    printf("Mutex : %p\n", mutex);
    pthread_mutexattr_t mattr;
    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutex, &mattr);
    pthread_mutexattr_destroy(&mattr);

    if (pthread_mutex_trylock(mutex)) {
        printf("Cannot acquire Lock. Some instance might be already running\n");
    } else {
        printf("Acquired Lock now sleeping...\n");
        sleep(25);
        pthread_mutex_unlock(mutex);
        pthread_mutex_destroy(mutex);
        shm_unlink(MYMUTEX);
    }
    return 0;
}

As far as I understand for creating a mutex shared between processes, it should be mapped to a shared memory and it should have the attribute PTHREAD_PROCESS_SHARED set. But the result I get when I run the program from two separate console is -

CONSOLE 1:

[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7faf2c57a000
Acquired Lock now sleeping...

CONSOLE 2:

[gbose@seadev20:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f6d5766a000
Acquired Lock now sleeping...

What am I missing here? My hunch is that initializing the mutex both the time is the root cause of this unexpected behavior - if that is correct then what else should have been done to check if the mutex is already initialized?

UPDATE : Handled the case where file for shared memory already exists by adding the O_EXCL as per comment by @Shawn but still I see that the memory address returned by mmap() is a new one as pasted above console output.

    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
    if (mutex_id < 0) {
        mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
    } else {
        if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
            printf("ftruncate failed\n");
            return -1;
        }
    }

Upvotes: 0

Views: 531

Answers (1)

Goutam Bose
Goutam Bose

Reputation: 35

Thanks @Shawn for pointing out to check if the shared memory exists or not first. Checking if the shared memory object already exists and if exists then not initializing the mutex again worked. Summary is if we reinitialize a mutex, then its lock information gets overridden hence it was not working.

    mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
    if (mutex_id < 0) {
        mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
        mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
        if (mutex == MAP_FAILED) {
            printf("mmap failed\n");
            return -1;
        }
    } else {
        if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
            printf("ftruncate failed\n");
            return -1;
        }
        mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
        if (mutex == MAP_FAILED) {
            printf("mmap failed\n");
            return -1;
        }
        pthread_mutexattr_t mattr;
        pthread_mutexattr_init(&mattr);
        pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(mutex, &mattr);
        pthread_mutexattr_destroy(&mattr);
    }
    printf("Mutex Id : %d\n", mutex_id);
    printf("Mutex : %p\n", mutex);

    if (pthread_mutex_trylock(mutex)) {
        printf("Cannot acquire Lock. Some instance might be already running\n");
    } else {
        printf("Acquired Lock now sleeping...\n");
        sleep(25);
        pthread_mutex_unlock(mutex);
        pthread_mutex_destroy(mutex);
        shm_unlink(MYMUTEX);
    }

CONSOLE 1

[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f3cd591c000
Acquired Lock now sleeping...

CONSOLE 2

[gbose@seadev2:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f09db159000
Cannot acquire Lock. Some instance might be already running

Upvotes: 0

Related Questions