56

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.

Caglayan DOKME
  • 948
  • 8
  • 21
Pithikos
  • 18,827
  • 15
  • 113
  • 136
  • 5
    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 Aug 12 '11 at 09:08
  • 7
    One of the gurus behind pthreads, David Butenhof, has an amusing recursive mutex rant at http://www.zaval.org/resources/library/butenhof1.html . So yeah, recursive mutexes are usually an indication of a faulty design. – janneb Aug 12 '11 at 09:29
  • 1
    @janneb: There are many correct uses for recursive mutexes, but yes I would strongly advise a beginner against them... – R.. GitHub STOP HELPING ICE Aug 12 '11 at 12:18
  • 1
    @R..: I think there're not so many correct uses for recursive mutexes that cannot be redesigned to avoid them. – Andriy Tylychko Oct 30 '11 at 11:07
  • 3
    @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 Oct 30 '11 at 21:48

4 Answers4

94

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
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Piotr Kukielka
  • 3,792
  • 3
  • 32
  • 40
20

To create a recursive mutex, you can either use:

#include <pthread.h>
/* Don't forget to check the return value! */
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,
                               int type);

where type is PTHREAD_MUTEX_RECURSIVE, or an initialiser.

For 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);
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
  • 1
    I get the error that I got in my earlier tries. The lines that don't compile are the three last ones and I use GCC with -pthread flag. pthread.h is also included. – Pithikos Aug 12 '11 at 08:49
  • 1
    Which error? You never mentioned one. Anyway, check the updated answer. – Michael Foukarakis Aug 12 '11 at 08:52
  • 1
    Yeah, which error indeed, and which OS? Solaris requires [g]cc -mt for multithreaded applications. A few implementations of "pthreads" are not 100% POSIX compliant. – jim mcnamara Oct 31 '11 at 14:47
18

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!)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 2
    Thanks for the info. Thus I found on MAC it is: static pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; – Val Nov 11 '14 at 08:46
2

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.

hamstergene
  • 24,039
  • 5
  • 57
  • 72