9

I've never had the chance to play with the pthreads library before, but I am reviewing some code involving pthread mutexes. I checked the documentation for pthread_mutex_lock and pthread_mutex_init, and my understanding from reading the man pages for both these functions is that I must call pthread_mutex_init before I call pthread_mutex_lock.

However, I asked a couple colleagues, and they think it is okay to call pthread_mutex_lock before calling pthread_mutex_init. The code I'm reviewing also calls pthread_mutex_lock without even calling pthread_mutex_init.

Basically, is it safe and smart to call pthread_mutex_lock before ever calling pthread_mutex_init (if pthread_mutex_init even gets called)?

EDIT: I also see some examples where pthread_mutex_lock is called when pthread_mutex_init is not used, such as this example

EDIT #2: Here is specifically the code I'm reviewing. Please note that the configure function acquires and attaches to some shared memory that does not get initialized. The Java code later on will call lock(), with no other native functions called in-between. Link to code

roschach
  • 8,390
  • 14
  • 74
  • 124
AleW
  • 185
  • 1
  • 10
  • 2
    Of *course* you shouldn't use it uninitialised... just like any other uninitialised data. However, there are ways to initialize a mutex without calling `pthread_mutex_init()` (eg. `PTHREAD_MUTEX_INITIALIZER` macro) – Dmitri Jul 27 '15 at 21:59
  • In the example you link to, they're declaring the mutex at file scope, so it's zeroed out... they may be making the assumption that the zeroed `pthread_mutex_t` is a valid state for an unlocked mutex... or the initializing code isn't shown. – Dmitri Jul 27 '15 at 22:04
  • I see. Sorry, but I just added in a second edit. It looks like the code I'm reviewing also does something similar, since shmget should zero out the memory region. Would it still be a good idea to make a call to pthread_mutex_init even in these cases? – AleW Jul 27 '15 at 22:07
  • 1
    The zeroed pthread_mutex_t is actually a valid state, but according to the standard, mutex'es must be initialized, so use PTHREAD_MUTEX_INITIALIZER or pthred_mutex_init() – Jens Munk Jul 27 '15 at 22:14
  • I'd either call `pthread_mutex_init()`, or at least use eg. `pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;` – Dmitri Jul 27 '15 at 22:14
  • the following link (which contains a lot of text) has a clear discussion of mutex's and why some need to be specifically initialized. – user3629249 Jul 27 '15 at 23:10
  • @FilipeGonçalves, I read that info from the linux man page for pthread_mutex_init() and pthread_mutex_lock() and pthread_mutex_destroy(). However, I deleted the comment because the linked stackoverflow page give a clearer description. – user3629249 Jul 27 '15 at 23:13

3 Answers3

10

Mutexes are variables containing state (information) that functions need to do their job. If no information was needed, the routine wouldn't need a variable. Likewise, the routine can't possibly function properly if you feed random garbage to it.

Most platforms do accept a mutex object filled with zero bytes. This is usually what pthread_mutex_init and PTHREAD_MUTEX_INITIALIZER create. As it happens, the C language also guarantees that uninitialized global variables are zeroed out when the program starts. So, it may appear that you don't need to initialize pthread_mutex_t objects, but this is not the case. Things that live on the stack or the heap, in particular, often won't be zeroed.

Calling pthread_mutex_init after pthread_lock is certain to have undesired consequences. It will overwrite the variable. Potential results:

  1. The mutex gets unlocked.
  2. A race condition with another thread attempting to get the lock, leading to a crash.
  3. Resources leaked in the library or kernel (but will be freed on process termination).
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Thanks a lot. I'll open a pull request on the code I'm reviewing later. It might not do much now, but at least it'll improve code quality and decrease risk in the future. – AleW Jul 28 '15 at 02:34
9

The POSIX standard says:

If mutex does not refer to an initialized mutex object, the behavior of pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() is undefined.

So you do need to initialise the mutex. This can be done either by a call to pthread_mutex_init(); or, if the mutex has static storage duration, by using the static initializer PTHREAD_MUTEX_INITIALIZER. Eg:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
caf
  • 233,326
  • 40
  • 323
  • 462
1

here is the text from the link I posted in a comment:

 Mutual exclusion locks (mutexes)  prevent  multiple  threads
 from simultaneously executing critical sections of code that
 access shared data (that is, mutexes are used  to  serialize
 the  execution  of  threads).  All mutexes must be global. A
 successful call for a mutex lock  by  way  of   mutex_lock()
 will  cause  another  thread that is also trying to lock the
 same mutex to block until the owner thread unlocks it by way
 of   mutex_unlock().  Threads  within  the  same  process or
 within other processes can share mutexes.

 Mutexes can synchronize threads within the **same  process**  or
 in  ***other   processes***.  Mutexes  can  be used to synchronize
 threads between processes if the mutexes  are  allocated  in
 writable  memory  and shared among the cooperating processes
 (see mmap(2)), and have been initialized for this task.

Initialize Mutexes are either intra-process or inter-process,
depending upon the argument passed implicitly or explicitly to the initialization of that mutex.
A statically allocated mutex does not need to be explicitly initialized;
by default, a statically allocated mutex is initialized with all zeros and its scope is set to be within the calling process.

 For inter-process synchronization, a mutex needs to be allo-
 cated   in  memory shared between these processes. Since the
 memory for such a mutex must be allocated dynamically,   the
 mutex needs to be explicitly initialized using mutex_init().




also, for inter-process synchronization,
besides the requirement to be allocated in shared memory,
the mutexes must also use the attribute PTHREAD_PROCESS_SHARED,
otherwise accessing the mutex from another process than its creator results in undefined behaviour
(see this: linux.die.net/man/3/pthread_mutexattr_setpshared):

The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a
mutex to be operated upon by any thread that has access to the memory
where the mutex is allocated, even if the mutex is allocated in memory that is shared by multiple processes
user3629249
  • 16,402
  • 1
  • 16
  • 17