According to the documentation a mutex can be initialized in two ways:
Using the init function:
pthread_mutex_t theMutex;
pthread_mutex_init(&theMutex, NULL);
Using an initializer macro:
pthread_mutex_t result = PTHREAD_MUTEX_INITIALIZER;
About the latter the documentation says:
In cases where default mutex attributes are appropriate, the macro 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.
Does this mean that it may only be used for static variables and not for local variables?
I wanted to use the following "factory function":
static pthread_mutex_t GetFastNativeMutex()
{
static pthread_mutex_t result = PTHREAD_MUTEX_INITIALIZER;
return result;
}
Because it would allow me to initialize mutexes in a C++ initializer list as follows:
MyClass() : myMutex(GetFastNativeMutex()) {}
Is this valid? (Btw in practice it works. Valgrind also doesn't complain.)
If I understood the documentation correctly then this should be ok:
#include <pthread.h>
static pthread_mutex_t m0 = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
However, when looking at the preprocessor output (using gcc -E main.cpp
) I see the following:
static pthread_mutex_t m0 = {0x32AAABA7, {0}};
static pthread_mutex_t m1 = {0x32AAABA7, {0}};
static pthread_mutex_t m2 = {0x32AAABA7, {0}};
It turns out that three times the same mutex was created. What am I doing wrong here?
A mutex can be statically initialized by assigning PTHREAD_MUTEX_INITIALIZER in its definition, as follows: pthread_mutex_t def_mutex = PTHREAD_MUTEX_INITIALIZER; A mutex must be initialized (either by calling pthread_mutex_init(), or statically) before it may be used in any other mutex functions.
That's simple: you need to ensure that the mutex is in a valid, known state before you use it. POSIX allows for the possibility that although default initialization of an object of type pthread_mutex_t yields a well-defined state, that state is not a valid, unlocked one at the pthreads level.
Use pthread_mutex_init(3C) to initialize the mutex pointed at by mp to its default value or to specify mutex attributes that have already been set with pthread_mutexattr_init() . The default value for mattr is NULL .
The pthread_mutex_init() function initializes a mutex with the specified attributes for use. The new mutex may be used immediately for serializing critical resources. If attr is specified as NULL, all attributes are set to the default mutex attributes for the newly created mutex.
Re "It turns out that three times the same mutex was created. What am I doing wrong here?"
You are doing nothing wrong here. The same mutex was not created three times. It looks like you are interpreting that 0x32AAABA7 as an address. It isn't. It is essentially an enum value, but with a Hamming code protection to (a) make it safe and (b) make it obscure. You have three distinct mutexes here.
Standard does not allow to copy mutexes by value or return them by value. See http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_init.html, the paragraph that explicitly talks about this, saying "IEEE Std 1003.1-2001 does not define assignment or equality for this type [pthread_mutex_t]"
The closest relative of pthread_mutex, WIN32 CriticalSection, is absolutely not copyable and not returnable by value. So your API will be very nonportable anyway.
I recommend against copying(returning) mutex by value even you can test it and it works.
Note that initializing a mutex is different from copying already initialized mutex.
Just because you can do it, doesn't mean you should.
The documentation clearly specifies that you use pthread_mutex_init
at runtime and the other macro for statically allocated mutexes, I don't see any reason for not doing so.
Your GetFastNativeMutex
is in no way a factory function. It always returns the copy of the same mutex, the point of factory is to abstract allocation and creation of a new object, not to reuse the same one all the time. So no, this is not valid for any usage that wouldn't be done by using the same mutex as a global variable.
A quote from here:
The result of referring to copies of mutex in calls to pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_unlock(), and pthread_mutex_destroy() is undefined
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With