开发者

Initializing a pthread mutex in shared memory

开发者 https://www.devze.com 2023-01-23 03:30 出处:网络
I can initialize a mutex in static memory with an initializer: pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;

I can initialize a mutex in static memory with an initializer:

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;

but how do I initialize one in shared memory where I have to allocate the memory separately from initializing the variable? Can I do a memcpy()?

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
memcpy(&globalmutex, &mymutex, sizeof(mymutex);

I thought I remembered reading a long time ago that when allocating a mute开发者_JS百科x into memory guaranteed to be initialized to zero's, it doesn't need initialization--intended for exactly this case--but I can't find that written down anywhere. Is that really true?--I notice that PTHREAD_MUTEX_INITIALIZER is defined as { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } on my redhat system.


You need to be careful here, not all implementations support mutexes that can work across processes.

PThreads itself supports this by use of the process shared attribute but, if you want that, you won't be using the default initialiser.

Instead you'll need to use pthread_mutex_init() after properly constructing a mutex attribute structure:

int pthread_mutex_init(
    pthread_mutex_t *mutex,
    const pthread_mutexattr_t *attr);

Best bet would be to just allocate space in shared memory then cast it to the correct type and pass it to the init function. I think that may be safer than copying it after the initialisation.


I have a similar problem and one approach I'm using is try to exclusively create the shared memory with (O_CREAT | O_RDWR | O_EXCL). If the creation succeeds, initialize the mutex in shared memory. If it failed, check if the shared memory already exists. If the shared memory exists, just open it with the flag O_RDWR and map to your mutex but assume it was already initialized by the process that successfully created it. Here's a bit of pseudo-code (POSIX + pthreads):

/* semaphore POST (block access from other processes) */
/* try to exclusively create */
int fd = shm_open (name, (O_CREAT | O_RDWR | O_EXCL), (S_IRUSR | S_IWUSR));
if (fd == -1) {
    /* failed creation */
    /* semaphore WAIT (wait until mutex initialized) */
    if (errno == EEXIST) {
        /* already exists, try to open */
        fd = shm_open (name, O_RDWR, (S_IRUSR | S_IWUSR));
        if (fd == -1) {
            /* check errors */
        } else {
            /* optionally check shared data size with fstat */
            fstat () ...
            /* map */
            mmap () ...
        }
    } else {
        /* check create errors */
    }
} else {
    /* successful creation! */
    /* truncate */
    ftruncate () ...
    /* map */
    mmap () ...
    /* initialize mutex */
    pthread_mutexattr_init () ...
    pthread_mutexattr_setpshared ( ... , PTHREAD_PROCESS_SHARED ) ...
    pthread_mutex_init () ...
    /* semaphore WAIT (wait until all processes are finished) */
}

A problem with this method is that there may be a race condition where another process opens it and attempts to lock the mutex immediately after the shared memory was created but before the mutex was initialized. I've never tried to test this scenario (it would be difficult to achieve) - I'm not working with a system that pushes those kinds of limits. However, a semaphore may be helpful in this situation to block access until the mutex is created. I added the semaphore logic in comments, but I'd appreciate feedback on it (the semaphores are not implemented or tested).

Edit

After a bit of thought, I realize the IPC semaphore guard may be better as a mutex and then we have to create a shared memory mutex recursively haha. But seriously, having a single process that solely manages the the creation, initialization, and destruction of a guard mutex could work.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号