Why is this an issue?
Mutexes are synchronization primitives that allow to manage concurrency.
Their use requires following a well-defined life-cycle.
- Mutexes need to be initialized (
pthread_mutex_init
) before being used. Once it is initialized, a mutex is in an
unlocked state.
- Mutexes need to be destroyed (
pthread_mutex_destroy
) to free the associated internal resources. Only unlocked
mutexes can be safely destroyed.
Before initialization or after destruction, a mutex is in an uninitialized state.
About this life-cycle, the following patterns should be avoided as they result in an undefined behavior:
- trying to initialize an initialized mutex
- trying to destroy an initialized mutex that is in a locked state
- trying to destroy an uninitialized mutex
- trying to lock an uninitialized mutex
- trying to unlock an uninitialized mutex
In C++, it is recommended to wrap mutex creation/destruction in a RAII class, as well as mutex lock/unlock. Those RAII classes will perform the
right operations, even in presence of exceptions.
Noncompliant code example
pthread_mutex_t mtx1;
void bad1(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_init(&mtx1);
}
void bad2(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_lock(&mtx1);
pthread_mutex_destroy(&mtx1);
}
void bad3(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_destroy(&mtx1);
pthread_mutex_destroy(&mtx1);
}
void bad4(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_destroy(&mtx1);
pthread_mutex_lock(&mtx1);
}
void bad5(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_destroy(&mtx1);
pthread_mutex_unlock(&mtx1);
}
Compliant solution
pthread_mutex_t mtx1;
void ok1(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_destroy(&mtx1);
}
void ok2(void)
{
pthread_mutex_init(&mtx1);
pthread_mutex_lock(&mtx1);
pthread_mutex_unlock(&mtx1);
pthread_mutex_destroy(&mtx1);
}
Resources