Mutexes are synchronization primitives that allow managing concurrency.
Their use requires following a well-defined life cycle:
- Mutexes need to be initialized (using
pthread_mutex_init
) before being used. Once it is initialized, a mutex is
in an unlocked state.
- Mutexes need to be destroyed (using
pthread_mutex_destroy
) to free the associated internal resources. Only
unlocked mutexes can be safely destroyed.
Before initialization and after destruction, a mutex is in an uninitialized state.
During a mutex' life cycle, the following patterns should be avoided as they result in undefined behavior:
- trying to initialize an already 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++11 and higher, std::mutex
is less error-prone and is supported by more platforms.
In C++03, it is recommended to wrap mutex creation/destruction in an RAII class, as well as mutex lock/unlock. Those RAII classes will perform the
right operations, even in the presence of exceptions.
What is the potential impact?
Failing to properly initialize or destroy a POSIX Thread Mutex leads to undefined behavior.
For programs that exercise undefined behavior, the compiler is no longer bound by the language specification. The application may crash or, even
worse, the application may appear to execute correctly while losing data or producing incorrect results. In a multi-threaded context, additionally,
the application may experience spurious deadlocks or data races.