Check if pthread_mutex is initialized
Asked Answered
C

2

9

Using pthreads it mandatory to call pthread_mutex_init() on any mutex before obtaining the lock.

According to POSIX the locking an uninitialized mutex is only defined for mutex with priority protection (opengroup : pthread_mutex_lock)

According to the manpage pthread_mutex_lock.3thr it should return EINVAL if called on an uninitalized mutex. Assuming portability is not an issue, would it be valid (a good idea?) to write code like:

pthread_mutex_t lock;

int ret = pthread_mutex_lock(&lock);
if (ret != 0){  
    if(ret == EINVAL){
        pthread_mutex_init(&lock, NULL);
    } else {
      /* other error */
    }
} 

Is there another way to check if a pthread_mutex has been initialized?

The whole scenario is part of a library (by politics unfortunately not C++) and I want to avoid to the maximum wrong usage. I.e. A client may initialize the object created twice, may pass the object to other functions before properly initialize it etc.

Currently there is an aditional flag in the object that marks if the mutex has been initialized, I was wondereing if this is really necessary.

Looking at the expansion of the macro PTHREAD_MUTEX_INITIALIZER for static mutex initialization it just expands into a struct with all members set to 0. Can I assume that is not required to call mutex_destroy if it is no longer required, given the ressource itself is freed (sure if noone else uses it)?

Update: Jens' answer is absolutely correct. The following program yields completely undefined behavior:

int main(int argc, char** argv)
{

pthread_mutex_t lock;
int ret = pthread_mutex_lock(&lock);
if (ret != 0) {
    printf(" ERR : %d %s \n", ret, strerror(ret));
    if (ret == EINVAL) {
        pthread_mutex_init(&lock, NULL);
    }
} else {
    printf(" ok \n");
}
pthread_mutex_unlock(&lock);
return 0;
}

Sometimes it deadlocks, somtimes it prints o.k. .....

Cilia answered 28/6, 2014 at 15:48 Comment(1)
Instead of trying to check whether a mutex is initialised or not, you should better go for knowing it.Cathcart
K
6

No you can't detect that. EINVAL may be returned for an uninitialized mutex, but it mustn't necessarily.

In addition POSIX states:

Attempting to initialize an already initialized mutex results in undefined behavior.

so you shouldn't try that.

The best way is to avoid that situation completely and to initialize the variable properly. This should be done with the macro PTHREAD_MUTEX_INITIALIZER.

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
Kakapo answered 28/6, 2014 at 16:31 Comment(3)
PTHREAD_MUTEX_INITIALIZER works if you want a default-type mutex. For other types you may need an accompanying pthread_once_t object and pthread_once call to initialize it, unless only one thread has the capacity to access the resource at the time the mutex is created (e.g. dynamically allocated objects that are only placed in an index visible to other threads after they're initialized).Royer
I ran into this same issue, and I'm just curious, if PTHREAD_MUTEX_INITIALIZER can be used to initialize a default-type mutex, why is the function pthread_mutex_init() a part of the library? Is it meant for dynamically allocated mutex's?Superintend
Yes, and for mutexes with non default properties.Kakapo
Z
0

To answer at least this part of the question,

Looking at the expansion of the macro PTHREAD_MUTEX_INITIALIZER for static mutex initialization it just expands into a struct with all members set to 0. Can I assume that is not required to call mutex_destroy if it is no longer required, given the ressource itself is freed (sure if noone else uses it)?

from the man page for pthread_mutex_init

PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes that are statically allocated. The effect shall be equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL, except that no error checks are performed.

from the man page for win32 pthread_mutex_init

In the Pthreads-w32 implementation, an application should still call pthread_mutex_destroy at some point to ensure that any resources consumed by the mutex are released.

Based on the fact that the man page states both static initialization and dynamic initialization are equivalent this leads me to believe that a static initialized mutex should always be destroyed when it is no longer in use. In the win32 version of pthreads man page this is explicitly stated. Moreover, destroying a mutex that was allocated using PTHREAD_MUTEX_INITIALIZER does not return an error, it happily returns 0, so there is no harm in doing it. At best it will free any resources no longer required and possibly poison the value of the mutex to mark it destroyed, or at worst, it will do nothing.

In conclusion, for portability I would always destroy any mutex that has been initialized even if it was done using a static initializer.

Zoe answered 11/3, 2021 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.