54
votes

I am a bit confused on how to declare a recursive mutex using pthread. What I try to do is have only one thread at a time be able to run a piece of code(including functions) but after scepticism I figured out that the use of mutexes would not work and that instead I should use recursive mutexes. Here is my code:

pthread_mutex_lock(&mutex);                   // LOCK

item = queue_peek(queue);                     // get last item in queue
item_buff=item;                               // save item to a buffer
queue_removelast(queue);                      // remove last item from queue

pthread_mutex_unlock(&mutex);                 // UNLOCK

So what I try to do is just read/remove from the queue serially.

The thing is that there isn't any example out there on how to declare recursive mutexes. Or there maybe a few but they don't compile for me.

4
You do not need recursive mutexes to solve this. The example you have given is fine, as long as the same mutex is used for all threads that access queue. For this reason, it would be usual to include the mutex within the queue itself: pthread_mutex_lock(&mutex->queue);, or if the queue is an opaque data structure, queue_lock(queue); (where queue_lock() locks the mutex internally).caf
One of the gurus behind pthreads, David Butenhof, has an amusing recursive mutex rant at zaval.org/resources/library/butenhof1.html . So yeah, recursive mutexes are usually an indication of a faulty design.janneb
@janneb: There are many correct uses for recursive mutexes, but yes I would strongly advise a beginner against them...R.. GitHub STOP HELPING ICE
@R..: I think there're not so many correct uses for recursive mutexes that cannot be redesigned to avoid them.Andriy Tylychko
@AndyT: The main class of important uses for recursive mutexes that I know of is when you have operations on a shared resource that need to individually be atomic, but also want to allow grouping several operations together as an atomic transaction. The classic example is stdio with flockfile.R.. GitHub STOP HELPING ICE

4 Answers

90
votes

The code from Michael Foukarakis is almost good but he initializes the mutex twice which leads to undefined behavior. It should just be:

pthread_mutex_t Mutex;
pthread_mutexattr_t Attr;

pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&Mutex, &Attr);

I actually use this code in production, and I know it works correctly on Linux, Solaris, HP-UX, AIX, Mac OSX and FreeBSD.

You also need to add proper linker flag to compile this:

AIX, Linux, FreeBSD:
CPLATFORM += -pthread

mingw32:
LDFLAGS += -lpthread
17
votes

On Linux (but this is non portable to other systems), if the mutex is a global or static variable, you could initialize it like

static pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

(and by the way, the example is from pthread_mutex_init(3) man pages!)

17
votes

To create a recursive mutex, use:

#include <pthread.h>
int pthread_mutexatttr_settype(pthread_mutexattr_t *attr,
                               int type);

where type is PTHREAD_MUTEX_RECURSIVE.

Don't forget to check the return value!

Example:

/* or PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
pthread_mutex_t       mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutexattr_t   mta;

or alternatively, initialize at runtime (don't do both, it's undefined behaviour):

pthread_mutexattr_init(&mta);
/* or PTHREAD_MUTEX_RECURSIVE_NP */
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);

pthread_mutex_init(&mutex, &mta);
2
votes

You need to add mutex attributes when creating the mutex.

Call pthread_mutexattr_init, then pthread_mutexattr_settype with PTHREAD_MUTEX_RECURSIVE then use these attributes with pthread_mutex_init. Read man pthread_mutexattr_init for more info.