It seems fairly common to have pthread mutexes that are intended to exist until the end of a program's lifetime. Often these are created using PTHREAD_MUTEX_INITIALIZER
.
Here's a short but complete code example showing what I'm referring to:
#include <pthread.h>
#include <iostream>
void log(char const * const message) {
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
std::cout << message << std::endl;
pthread_mutex_unlock(&mutex);
}
struct Object final {
Object() { log("Object::Object()"); }
~Object() { log("Object::~Object()"); }
};
Object const object;
int main(int const argc, const char * argv[]) {
log("main()");
// Here the program would enter a main loop, with log() potentially being
// called from multiple threads at various times.
}
Output:
Object::Object()
main()
Object::~Object()
Error-checking and RAII wrapping for the lock are omitted for brevity.
This example includes a thread-safe (at least that's the intent) logging function that's intended to be available throughout the lifetime of the program, including during deinitialization of objects with static storage duration, possibly (although not in this case) across multiple translation units, meaning that deinitialization order may be indeterminate.
The issue is that there's no opportunity to safely destroy the mutex, as it may be needed at any point in the program's lifetime. (In practice I don't intend to have objects with static storage duration and nontrivial destructors, but I'm interested in addressing the issue nonetheless.)
The first question that arises is whether mutexes initialized using PTHREAD_MUTEX_INITIALIZER
need to be destroyed using pthread_mutex_destroy()
. At least some versions of the documentation include this wording:
In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes. 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.
This suggests that if pthread_mutex_destroy()
is expected to be called on mutexes initialized using pthread_mutex_init()
, then it's expected to be called on mutexes initialized using PTHREAD_MUTEX_INITIALIZER
as well.
However, in searching online and here on Stack Overflow, I've found disagreement as to whether it's required. For example, here someone offers the following quote from a book on Linux development:
It is not necessary to call pthread_mutex_destroy() on a mutex that was statically initialized using PTHREAD_MUTEX_INITIALIZER.
On the other hand, in this thread it's argued that explicitly destroying such a mutex is in fact required.
I've also seen it argued that it's not necessary to clean up mutexes in these sorts of circumstances regardless of how they're initialized because the resources will be reclaimed anyway. (This would presumably be the same logic behind the 'construct on first use and deliberately leak memory' idiom sometimes used for singletons and other objects with static storage duration.)
I found a number of other threads that touch on the subject, with a mix of opinions on if/how mutexes should be destroyed. I'll also mention that I believe I've seen production code from credible sources that initializes mutexes with PTHREAD_MUTEX_INITIALIZER
and never destroys them.
I've gone into some detail here as a matter of due diligence, but my question is (I think) fairly simple. It would be useful to have mutexes that are available from initialization to the very end of the program's lifetime. I suspect not cleaning up such mutexes wouldn't cause any problems, but that approach troubles me. And even though some say mutexes initialized using PTHREAD_MUTEX_INITIALIZER
don't need to be cleaned up, that seems contrary to the documentation and to various claims made by others.
In summary, is there a safe and reasonable way to manage pthread mutexes that are intended to be available until the end of a program's lifetime? Is there any standard best practice here that I've failed to stumble upon in my search?