Reputation: 343
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. .....
Upvotes: 9
Views: 13750
Reputation: 248
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.
Upvotes: 0
Reputation: 78973
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;
Upvotes: 6