You are on page 1of 13

PTHREADS: MUTEXES

1 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

www2.chrishardick.com

PTHREADS: MUTEXES
the basic pthread synchronization mechanism
mutex stands for mutual exclusion.
the job of a mutex is to guarantee mutual exclusive access to a
given resource (or set of resources)
the most common method to synchronize common resources
(global data, file descriptors, etc.) among threads is to ensure
that only one thread is allowed to interact with the shared
resource @ a given time. I.e. access to the shared resource is
mutually exclusive (mutex)
the most basic (& most common) usage is to create one mutex
for each shared resource and to surround all access to the
shared resouce w/ mutex_lock() & mutex_unlock() calls

1. MUTEX DATATYPE: PTHREAD_MUTEX_T


#include <pthread.h>
pthread_mutex_t my_mutex;

3/3/2016 12:50 AM

PTHREADS: MUTEXES

2 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

an opaque type -- (see Opaque Datatypes)


never copy a mutex - the result is undefined (it's opaque)
if you need access to a mutex, you can copy a pointer to a
mutex (into a function, etc.)

2. MUTEX CREATION & DESTRUCTION


In order to use a mutex, it must first be initialized (and initialized
only once)
There are two ways a mutex can be initialized
1. static initialization
2. dynamic initialization
A. STATIC INITIALIZATION
/*
* statically initialize a mutex using
PTHREAD_MUTEX_INITIALIZER macro
*/
pthread_mutex_t StaticMutex =
PTHREAD_MUTEX_INITIALIZER;
statically initializes a mutex with default attributes.
if you need to specify attributes, you must use dynamic
initialization

3/3/2016 12:50 AM

PTHREADS: MUTEXES

3 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

if you dynamically allocate a mutex, you must use dynamic


initialization
mutexes which are initialized statically do NOT need to be
destroyed
B. DYNAMIC INITIALIZATION
/*
* dynamically initialize a mutex
*
* RETURN
* ======
* 0 = success
* else - see discussion on pthreads and errors
*/
int pthread_mutex_init (pthread_mutex_t*
p_Mutex,

// in
pthread_mutexattr_t*

p_MutexAttr);

// in: pass NULL for

default attributes
mutexes which are dynamically initialized need to be destroyed
using pthread_mutex_destroy()
you can safely destroy a mutex which has no thread(s) blocked
on it & is unlocked
how do you know if no threads are blocked on the mutex & that
it is unlocked? You have to have a solid grasp of the program

3/3/2016 12:50 AM

PTHREADS: MUTEXES

4 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

logic!!!
/*
* destroy a dynamically initialized mutex
*
* RETURN
* ======
* 0 = success
* else - see discussion on pthreads and errors
*/
int pthread_mutex_destroy (pthread_mutex_t*
p_Mutex)

// in

/*
* an example
*/
#include <pthread.h>
#include <string.h>

// for strerror_r()

char szEMsg[80];
pthread_mutex_t* p_DynamicMutex =
(pthread_mutex_t*) malloc
(sizeof(pthread_mutex_t));
int iRC = pthread_mutex_init (p_DynamicMutex,
NULL);
if (iRC != 0)
{
3/3/2016 12:50 AM

PTHREADS: MUTEXES

5 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

strerror_r(iRC, szEMsg,
sizeof(szEMsg));
cout << "ERR: UNABLE TO INIT DYNAMIC
MUTEX: " << szEMsg << endl;
return false;
}
...
iRC = pthread_mutex_destroy (p_DynamicMutex);
if (iRC != 0)
{
strerror_r(iRC, szEMsg,
sizeof(szEMsg));
cout << "ERR: UNABLE TO DESTROY
DYNAMIC MUTEX: " << szEMsg << endl;
return false;
}

3. LOCKING & UNLOCKING A MUTEX


Use pthread_mutex_lock( ) to lock a mutex
/*
* lock a mutex - blocking call
* - if mutex is not already locked, you will

3/3/2016 12:50 AM

PTHREADS: MUTEXES

6 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

obtain the lock & own the mutex


* - if mutex is already locked, you will block
*
* RETURN
* ======
* 0 = success
* else - see discussion on pthreads and errors
*/
int pthread_mutex_lock (pthread_mutex_t*
p_Mutex);

// in

be careful NOT to lock a mutex when the calling thread already


has the mutex locked; the behavior is undefined. On some
systems, pthread_mutex_lock() will return an error, on other
systems, you'll be in a self-deadlock and never return
Use pthread_mutex_unlock( ) to unlock a mutex
You can ONLY unlock a mutex which is currently locked
(owned) by the current thread
2 corollaries: (1) you cannot unlock a mutex which is not locked
& (2) you cannot unlock a mutex which was locked by another
thread
mutex owner: the thread which obtained the lock on the mutex
/*
* unlock a mutex
* - mutex must be owned by current thread
* - unlock mutex & release ownership

3/3/2016 12:50 AM

PTHREADS: MUTEXES

7 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

*
* RETURN
* ======
* 0 = success
* else - see discussion on pthreads and errors
*/
int pthread_mutex_unlock (pthread_mutex_t*
p_Mutex);

// in

Non-blocking Mutex Locks: pthread_mutex_trylock( )


/*
* lock a mutex - non-blocking version
* - if mutex is not already locked, you will
obtain the lock & own the mutex
* - if mutex is already locked,
pthread_mutex_trylock() will return
immediately wth return value EBUSY
*
* RETURN
* ======
* 0 = success
* EBUSY = mutex is currently locked
* else - see discussion on pthreads and errors
*/
int pthread_mutex_trylock (pthread_mutex_t*
p_Mutex);

// in

A simple example
/*
* All accesses and modifications to x should
3/3/2016 12:50 AM

PTHREADS: MUTEXES

8 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

be bracketed by calls to
* pthread_mutex_lock() and
pthread_mutex_unlock() as follows:
*/
pthread_mutex_lock(&Mutex);
/*
* operate on x
*/
pthread_mutex_unlock(&Mutex);

4. MUTEX SIZE
How much code should be within a mutex (i.e. how much
data--and other shared resources--should be protected by a
single mutex)?
When converting existing non thread-safe code (e.g. an existing
C library or (even worse) an existing fortran library), it's easiest
to lock before entering and unlock after returning. This is known
a a BIG MUTEX and depending on your situation, it might be
your best (or only) solution
As a general rule, resources which are usually used together
should use the same mutex. Unrelated resources should use
separate mutexes

5. AVOIDING DEADLOCKS
3/3/2016 12:50 AM

PTHREADS: MUTEXES

9 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

Anytime your code need to hold more than one mutex @ a time,
you have to be careful to avoid deadlock
The classic deadlock
Thread 1
Thread 2
========
========
lock mutex_a
lock mutex_b
|

lock mutex_b
lock mutex_a
- blocked forever waiting for mutex_b

blocked forever waiting for mutex_a


Common techniques to avoid deadlocks are:
1. establish a locking hierarchy
2. spin lock
3. chaining
A. ESTABLISH A LOCKING HIERARCHY
If a thread needs to hold multiple locks simultaneously, establish
a hierarchy
For example, mutex_a and mutex_b protect data which
sometimes needs to be accessed simultaneously, establish a

3/3/2016 12:50 AM

PTHREADS: MUTEXES

10 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

rule such that in order to lock both mutex_a and mutex_b,


mutex_a must first be locked, followed by mutex_b
Make sure you really need to hold both locks simultaneously.
I.e. is it possible to release the 1st lock prior to obtaining the 2nd
lock?
Use whatever order makes the most sense -- so long as you
always use the same order
Make a function to lock the set of mutexes (to enforce the
correct order) -- be sure to document
Unlocking the mutexes in whatever order makes the most
sense. Unlocking can never result in deadlock, but some orders
will probably be more effecient than others
For a locking hierarchy, it usually makes the most sense to
unlock in the same order
Make another function to unlock the set of mutexes
Thread 1
Thread 2
========
========
lock mutex_a

lock mutex_b
lock mutex_a (blocked)
|

perform processing

3/3/2016 12:50 AM

PTHREADS: MUTEXES

11 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

unlock mutex_a

unlock mutex_b
wake up (obtained mutex_a)
|
lock mutex_b
...

perform processing
|
unlock mutex_a
unlock mutex_b
|
...
B. SPIN LOCK
Lock the first mutex normally (blocking), but for any additional
mutexes - use non-blocking mutexes (pthread_mutex_trylock())
If any lock fails, unlock in reverse order and try again
Unlocking the mutexes in the reverse order reduces the
spinning for other threads
Thread 1
Thread 2
========
========

3/3/2016 12:50 AM

PTHREADS: MUTEXES

12 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

lock mutex_a

try-lock mutex_b
lock mutex_a (blocked)
|

perform processing

unlock mutex_b

unlock mutex_a

|
wake up (obtained mutex_a)
...
try-lock mutex_b
|
perform processing
|
unlock mutex_b
unlock mutex_a
C. CHAINING
Useful for traversing linked lists and other tree data structures
A type of locking hierarchy
Lock #1, Lock #2, Unlock #1, Lock #3, Unlock #2
Thread 1
========

3/3/2016 12:50 AM

PTHREADS: MUTEXES

13 of 13

about:reader?url=http://www2.chrishardick.com/Notes/Computing/C/pth...

lock head node


head node processing
|
traverse branch locking first node
unlock head node
first node processing
Back to PTHREADS

3/3/2016 12:50 AM

You might also like