JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Multithreaded Programming Guide
search filter icon
search icon

Document Information

Preface

1.  Covering Multithreading Basics

2.  Basic Threads Programming

3.  Thread Attributes

4.  Programming with Synchronization Objects

Mutual Exclusion Lock Attributes

Initializing a Mutex Attribute Object

pthread_mutexattr_init Syntax

pthread_mutexattr_init Return Values

Destroying a Mutex Attribute Object

pthread_mutexattr_destroy Syntax

pthread_mutexattr_destroy Return Values

Setting the Scope of a Mutex

pthread_mutexattr_setpshared Syntax

pthread_mutexattr_setpshared Return Values

Getting the Scope of a Mutex

pthread_mutexattr_getpshared Syntax

pthread_mutexattr_getpshared Return Values

Setting the Mutex Type Attribute

pthread_mutexattr_settype Syntax

pthread_mutexattr_settype Return Values

Getting the Mutex Type Attribute

pthread_mutexattr_gettype Syntax

pthread_mutexattr_gettype Return Values

Setting the Mutex Attribute's Protocol

pthread_mutexattr_setprotocol Syntax

pthread_mutexattr_setprotocol Return Values

Getting the Mutex Attribute's Protocol

pthread_mutexattr_getprotocol Syntax

pthread_mutexattr_getprotocol Return Values

Setting the Mutex Attribute's Priority Ceiling

pthread_mutexattr_setprioceiling Syntax

pthread_mutexattr_setprioceiling Return Values

Getting the Mutex Attribute's Priority Ceiling

pthread_mutexattr_getprioceiling Syntax

pthread_mutexattr_getprioceiling Return Values

Setting the Mutex's Priority Ceiling

pthread_mutex_setprioceiling Syntax

pthread_mutex_setprioceiling Return Values

Getting the Mutex's Priority Ceiling

pthread_mutex_getprioceiling Syntax

pthread_mutex_getprioceiling Return Values

Setting the Mutex's Robust Attribute

pthread_mutexattr_setrobust_np Syntax

pthread_mutexattr_setrobust_np Return Values

Getting the Mutex's Robust Attribute

pthread_mutexattr_getrobust_np Syntax

pthread_mutexattr_getrobust_np Return Values

Using Mutual Exclusion Locks

Initializing a Mutex

pthread_mutex_init Syntax

pthread_mutex_init Return Values

Making a Mutex Consistent

pthread_mutex_consistent_np Syntax

pthread_mutex_consistent_np Return Values

Locking a Mutex

pthread_mutex_lock Syntax

pthread_mutex_lock Return Values

Unlocking a Mutex

pthread_mutex_unlock Syntax

pthread_mutex_unlock Return Values

Locking a Mutex Without Blocking

pthread_mutex_trylock Syntax

pthread_mutex_trylock Return Values

Locking a Mutex Before a Specified Absolute Time

pthread_mutex_timedlock() Syntax

pthread_mutex_timedlock() Return Values

Locking a Mutex Within a Specified Time Interval

pthread_mutex_reltimedlock_np() Syntax

pthread_mutex_reltimedlock_np() Return Values

Destroying a Mutex

pthread_mutex_destroy Syntax

pthread_mutex_destroy Return Values

Code Examples of Mutex Locking

Examples of Using Lock Hierarchies

Examples of Using Nested Locking With a Singly-Linked List

Example of Nested Locking With a Circularly-Linked List

Using Spin Locks

Initializing a Spin Lock

pthread_spin_init() Syntax

pthread_spin_init() Return Values

Acquiring a Spin Lock

pthread_spin_lock() Syntax

pthread_spin_lock() Return Values

Acquiring a Non-Blocking Spin Lock

pthread_spin_trylock() Syntax

pthread_spin_trylock() Return Values

Unlocking a Spin Lock

pthread_spin_unlock() Syntax

pthread_spin_unlock() Return Values

Destroying a Spin Lock

pthread_spin_destroy() Syntax

pthread_spin_destroy() Return Values

Condition Variable Attributes

Initializing a Condition Variable Attribute

pthread_condattr_init Syntax

pthread_condattr_init Return Values

Removing a Condition Variable Attribute

pthread_condattr_destroy Syntax

pthread_condattr_destroy Return Values

Setting the Scope of a Condition Variable

pthread_condattr_setpshared Syntax

pthread_condattr_setpshared Return Values

Getting the Scope of a Condition Variable

pthread_condattr_getpshared Syntax

pthread_condattr_getpshared Return Values

Setting the Clock Selection Condition Variable

pthread_condattr_setclock Syntax

pthread_condattr_setclock Returns

Getting the Clock Selection Condition Variable

pthread_condattr_getclock Syntax

pthread_condattr_getclock Returns

Using Condition Variables

Initializing a Condition Variable

pthread_cond_init Syntax

pthread_cond_init Return Values

Blocking on a Condition Variable

pthread_cond_wait Syntax

pthread_cond_wait Return Values

Unblocking One Thread

pthread_cond_signal Syntax

pthread_cond_signal Return Values

Blocking Until a Specified Time

pthread_cond_timedwait Syntax

pthread_cond_timedwait Return Values

Blocking For a Specified Interval

pthread_cond_reltimedwait_np Syntax

pthread_cond_reltimedwait_np Return Values

Unblocking All Threads

pthread_cond_broadcast Syntax

pthread_cond_broadcast Return Values

Destroying the Condition Variable State

pthread_cond_destroy Syntax

pthread_cond_destroy Return Values

Lost Wake-Up Problem

Producer and Consumer Problem

Synchronization With Semaphores

Named and Unnamed Semaphores

Counting Semaphores Overview

Initializing a Semaphore

sem_init Syntax

Initializing Semaphores With Intraprocess Scope

Initializing Semaphores With Interprocess Scope

sem_init Return Values

Incrementing a Semaphore

sem_post Syntax

sem_post Return Values

Blocking on a Semaphore Count

sem_wait Syntax

sem_wait Return Values

Decrementing a Semaphore Count

sem_trywait Syntax

sem_trywait Return Values

Destroying the Semaphore State

sem_destroy Syntax

sem_destroy Return Values

Producer and Consumer Problem Using Semaphores

Read-Write Lock Attributes

Initializing a Read-Write Lock Attribute

pthread_rwlockattr_init Syntax

pthread_rwlockattr_init Return Values

Destroying a Read-Write Lock Attribute

pthread_rwlockattr_destroy Syntax

pthread_rwlockattr_destroy Return Values

Setting a Read-Write Lock Attribute

pthread_rwlockattr_setpshared Syntax

pthread_rwlockattr_setpshared Return Values

Getting a Read-Write Lock Attribute

pthread_rwlockattr_getpshared Syntax

pthread_rwlockattr_getpshared Return Values

Using Read-Write Locks

Initializing a Read-Write Lock

pthread_rwlock_init Syntax

pthread_rwlock_init Return Values

Acquiring the Read Lock on Read-Write Lock

pthread_rwlock_rdlock Syntax

pthread_rwlock_rdlock Return Values

Acquiring a Read Lock on a Read-Write Lock Before a Specified Absolute Time

pthread_rwlock_timedrdlock Syntax

pthread_rwlock_timedrdlock Return Values

Acquiring a Non-Blocking Read Lock on a Read-Write Lock

pthread_rwlock_tryrdlock Syntax

pthread_rwlock_tryrdlock Return Values

Acquiring the Write Lock on a Read-Write Lock

pthread_rwlock_wrlock Syntax

pthread_rwlock_wrlock Return Values

Acquiring a Non-blocking Write Lock on a Read-Write Lock

pthread_rwlock_trywrlock Syntax

pthread_rwlock_trywrlock Return Values

Acquiring a Write Lock on a Read-Write Lock Before a Specified Absolute Time

pthread_rwlock_timedwrlock Syntax

pthread_rwlock_timedwrlock Returns

Unlocking a Read-Write Lock

pthread_rwlock_unlock Syntax

pthread_rwlock_unlock Return Values

Destroying a Read-Write Lock

pthread_rwlock_destroy Syntax

pthread_rwlock_destroy Return Values

Using Barrier Synchronization

Initializing a Synchronization Barrier

pthread_barrier_init() Syntax

pthread_barrier_init() Return Values

Waiting for Threads to Synchronize at a Barrier

pthread_barrier_wait() Syntax

pthread_barrier_wait() Return Values

Destroying a Synchronization Barrier

pthread_barrier_destroy Syntax

pthread_barrier_destroy Return Values

Initializing a Barrier Attributes Object

pthread_barrierattr_init() Syntax

pthread_barrierattr_init() Return Values

Setting a Barrier Process-Shared Attribute

pthread_barrierattr_setpshared() Syntax

pthread_barrierattr_setpshared() Return Values

Getting a Barrier Process-Shared Attribute

pthread_barrierattr_getpshared() Syntax

pthread_barrierattr_getpshared() Return Values

Destroying a Barrier Attributes Object

pthread_barrierattr_destroy() Syntax

pthread_barrierattr_destroy() Return Values

Synchronization Across Process Boundaries

Producer and Consumer Problem Example

Comparing Primitives

5.  Programming With the Solaris Software

6.  Programming With Solaris Threads

7.  Safe and Unsafe Interfaces

8.  Compiling and Debugging

9.  Programming Guidelines

A.  Extended Example: A Thread Pool Implementation

Index

Using Mutual Exclusion Locks

Table 4-3 lists the functions that manipulate mutex locks.

Table 4-3 Routines for Mutual Exclusion Locks

Operation
Related Function Description
Initialize a mutex
Make mutex consistent
Lock a mutex
Unlock a mutex
Lock with a nonblocking mutex
Lock a mutex before a specified time
Lock a mutex within a specified time interval
Destroy a mutex

The default scheduling policy, SCHED_OTHER, does not specify the order in which threads can acquire a lock. When multiple SCHED_OTHER threads are waiting for a mutex, the order of acquisition is undefined. Under the SCHED_FIFO and SCHED_RR real-time scheduling policies, the behavior is to unblock waiting threads in priority order.

Initializing a Mutex

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 .

pthread_mutex_init Syntax
int pthread_mutex_init(pthread_mutex_t *restrict mp,
          const pthread_mutexattr_t *restrict mattr);
#include <pthread.h>

pthread_mutex_t mp = PTHREAD_MUTEX_INITIALIZER;
pthread_mutexattr_t mattr;
int ret;

/* initialize a mutex to its default value */
ret = pthread_mutex_init(&mp, NULL);

/* initialize a mutex */
ret = pthread_mutex_init(&mp, &mattr); 

When the mutex is initialized, the mutex is in an unlocked state. The mutex can be in memory that is shared between processes or in memory private to a process.


Note - For a mutex that is being initialized with the PTHREAD_MUTEX_ROBUST_NP attribute, the mutex memory must be cleared to zero before initialization.


The effect of mattr set to NULL is the same as passing the address of a default mutex attribute object, but without the memory overhead.

Use the macro PTHREAD_MUTEX_INITIALIZER to initialize statically defined mutexes to their default attributes.

Do not reinitialize or destroy a mutex lock while other threads are using the mutex. Program failure results if either action is not done correctly. If a mutex is reinitialized or destroyed, the application must be sure the mutex is not currently in use.

pthread_mutex_init Return Values

pthread_mutex_init() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occurs, the function fails and returns the corresponding value.

EBUSY

Description: The implementation has detected an attempt to reinitialize the object referenced by mp, a previously initialized but not yet destroyed mutex.

EINVAL

Description: The mattr attribute value is invalid. The mutex has not been modified.

EFAULT

Description: The address for the mutex pointed at by mp is invalid.

Making a Mutex Consistent

If the owner of a robust mutex terminates without unlocking the mutex, the mutex is unlocked and marked inconsistent. The next owner acquires the lock with an EOWNERDEAD return code.

pthread_mutex_consistent_np() makes the mutex object, mutex, consistent after the death of its owner.

pthread_mutex_consistent_np Syntax
#include <pthread.h> 
int pthread_mutex_consistent_np(pthread_mutex_t *mutex); 

Call pthread_mutex_lock() to acquire the inconsistent mutex. The EOWNWERDEAD return value indicates an inconsistent mutex.

Call pthread_mutex_consistent_np() while holding the mutex acquired by a previous call to pthread_mutex_lock().

The critical section protected by the mutex might have been left in an inconsistent state by a failed owner. In this case, make the mutex consistent only if you can make the critical section protected by the mutex consistent.

Calls to pthread_mutex_lock(), pthread_mutex_unlock() , and pthread_mutex_trylock() for a consistent mutex behave in the normal manner.

The behavior of pthread_mutex_consistent_np() for a mutex that is not inconsistent, or is not held, is undefined.

pthread_mutex_consistent_np Return Values

pthread_mutex_consistent_np() returns zero after completing successfully. Any other return value indicates that an error occurred.

pthread_mutex_consistent_np() fails if the following condition occurs:

EINVAL

Description: The current thread does not own the mutex or the mutex is not a PTHREAD_MUTEX_ROBUST_NP mutex having an inconsistent state.

Locking a Mutex

Use pthread_mutex_lock(3C) to lock the mutex pointed to by mutex.

pthread_mutex_lock Syntax
int  pthread_mutex_lock(pthread_mutex_t *mutex); 
#include <pthread.h>

pthread_mutex_t mutex;
int ret;

ret = pthread_ mutex_lock(&mp); /* acquire the mutex */

When pthread_mutex_lock() returns, the mutex is locked. The calling thread is the owner. If the mutex is already locked and owned by another thread, the calling thread blocks until the mutex becomes available.

If the mutex type is PTHREAD_MUTEX_NORMAL , deadlock detection is not provided. Attempting to relock the mutex causes deadlock. If a thread attempts to unlock a mutex not locked by the thread or a mutex that is unlocked, undefined behavior results.

If the mutex type is PTHREAD_MUTEX_ERRORCHECK , then error checking is provided. If a thread attempts to relock a mutex that the thread has already locked, an error is returned. If a thread attempts to unlock a mutex not locked by the thread or a mutex that is unlocked, an error is returned.

If the mutex type is PTHREAD_MUTEX_RECURSIVE , then the mutex maintains the concept of a lock count. When a thread successfully acquires a mutex for the first time, the lock count is set to 1. Every time a thread relocks this mutex, the lock count is incremented by 1. Every time the thread unlocks the mutex, the lock count is decremented by 1. When the lock count reaches 0, the mutex becomes available for other threads to acquire. If a thread attempts to unlock a mutex not locked by the thread or a mutex that is unlocked, an error is returned.

The mutex type PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_NORMAL.

pthread_mutex_lock Return Values

pthread_mutex_lock() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occurs, the function fails and returns the corresponding value.

EAGAIN

Description: The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.

EDEADLK

Description: The current thread already owns the mutex.

If the mutex was initialized with the PTHREAD_MUTEX_ROBUST_NProbustness attribute, pthread_mutex_lock() may return one of the following values:

EOWNERDEAD

Description: The last owner of this mutex terminated while holding the mutex. This mutex is now owned by the caller. The caller must attempt to make the state protected by the mutex consistent.

If the caller is able to make the state consistent, call pthread_mutex_consistent_np() for the mutex and unlock the mutex. Subsequent calls to pthread_mutex_lock() behave normally.

If the caller is unable to make the state consistent, do not call pthread_mutex_init() for the mutex. Unlock the mutex instead. Subsequent calls to pthread_mutex_lock() fail to acquire the mutex and return an ENOTRECOVERABLE error code.

If the owner that acquired the lock with EOWNERDEAD terminates while holding the mutex, the next owner acquires the lock with EOWNERDEAD.

ENOTRECOVERABLE

Description: The mutex you are trying to acquire was protecting state left irrecoverable by the mutex's previous owner. The mutex has not been acquired. This irrecoverable condition can occur when:

ENOMEM

Description: The limit on the number of simultaneously held mutexes has been exceeded.

Unlocking a Mutex

Use pthread_mutex_unlock(3C) to unlock the mutex pointed to by mutex.

pthread_mutex_unlock Syntax
int pthread_mutex_unlock(pthread_mutex_t *mutex); 
#include <pthread.h>

pthread_mutex_t mutex;
int ret;

ret = pthread_mutex_unlock(&mutex); /* release the mutex */

pthread_mutex_unlock() releases the mutex object referenced by mutex. The manner in which a mutex is released is dependent upon the mutex's type attribute. If threads are blocked on the mutex object when pthread_mutex_unlock() is called and the mutex becomes available, the scheduling policy determines which thread acquires the mutex. For PTHREAD_MUTEX_RECURSIVE mutexes, the mutex becomes available when the count reaches zero and the calling thread no longer has any locks on this mutex.

pthread_mutex_unlock Return Values

pthread_mutex_unlock() returns zero after completing successfully. Any other return value indicates that an error occurred. When the following condition occurs, the function fails and returns the corresponding value.

EPERM

Description: The current thread does not own the mutex.

Locking a Mutex Without Blocking

Use pthread_mutex_trylock(3C) to attempt to lock the mutex pointed to by mutex, and return immediately if the mutex is already locked.

pthread_mutex_trylock Syntax
int pthread_mutex_trylock(pthread_mutex_t *mutex); 
#include <pthread.h>

pthread_mutex_t mutex;
int ret;

ret = pthread_mutex_trylock(&mutex); /* try to lock the mutex */

pthread_mutex_trylock() is a nonblocking version of pthread_mutex_lock(). If the mutex object referenced by mutex is currently locked by any thread, including the current thread, the call returns immediately. Otherwise, the mutex is locked and the calling thread is the owner.

pthread_mutex_trylock Return Values

pthread_mutex_trylock() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occurs, the function fails and returns the corresponding value.

EBUSY

Description: The mutex could not be acquired because the mutex pointed to by mutex was already locked.

EAGAIN

Description: The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.

If the symbol _POSIX_THREAD_PRIO_INHERIT is defined, the mutex is initialized with the protocol attribute value PTHREAD_PRIO_INHERIT . Additionally, if the robustness argument of pthread_mutexattr_setrobust_np() is PTHREAD_MUTEX_ROBUST_NP, the function fails and returns one of the following values:

EOWNERDEAD

Description: See the discussion in pthread_mutex_lock Return Values.

ENOTRECOVERABLE

Description: See the discussion in pthread_mutex_lock Return Values.

ENOMEM

Description: The limit on the number of simultaneously held mutexes has been exceeded.

Locking a Mutex Before a Specified Absolute Time

Use the pthread_mutex_timedlock(3C) function to attempt until a specified time to lock a mutex object.

This function works as the pthread_mutex_lock() function does, except that it does not block indefinitely. If the mutex is already locked, the calling thread is blocked until the mutex becomes available, but only until the timeout is reached. If the timeout occurs before the mutex becomes available, the function returns.

pthread_mutex_timedlock() Syntax
int  pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, 
          const struct timespec *restrict abs_timeout);
#include <pthread.h>
#include <time.h>

pthread_mutex_t mutex;
timestruct_t abs_timeout;
int ret;

ret = pthread_mutex_timedlock(&mutex,  &abs_timeout); 
pthread_mutex_timedlock() Return Values

The pthread_mutex_timedlock() function return 0 if it locks the mutex successfully. Otherwise, an error number is returned to indicate the error.

EINVAL

Description: The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's priority is higher than the mutex's current priority ceiling.

Description: The value specified by mutex does not refer to an initialized mutex object.

Description: The process or thread would have blocked, and the abs_timeout parameter specified a nanoseconds field value less than 0 or greater than or equal to 1000 million.

ETIMEDOUT

Description: The mutex could not be locked before the specified timeout expired.

See the discussion in pthread_mutex_lock Return Values.

Locking a Mutex Within a Specified Time Interval

Use the pthread_mutex_reltimedlock_np(3C) function to attempt until a specified amount of time elapses to lock a mutex object.

The timeout expires when the time interval specified by rel_timeout passes, as measured by the CLOCK_REALTIME clock, or if the time interval specified by rel_timeout is negative at the time of the call.

pthread_mutex_reltimedlock_np() Syntax
int  pthread_mutex_reltimedlock_np(pthread_mutex_t *restrict mutex, 
          const struct timespec *restrict rel_timeout);
#include <pthread.h>
#include <time.h>

pthread_mutex_t mutex;
timestruct_t rel_timeout;
int ret;

ret = pthread_mutex_reltimedlock_np(&mutex,  &rel_timeout); 
pthread_mutex_reltimedlock_np() Return Values

The pthread_mutex_reltimedlock_np() function returns 0 if it locks the mutex successfully. Otherwise, an error number is returned to indicate the error.

EINVAL

Description: The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's priority is higher than the mutex's current priority ceiling.

Description: The value specified by mutex does not refer to an initialized mutex object.

Description: The process or thread would have blocked, and the abs_timeout parameter specified a nanoseconds field value less than 0 or greater than or equal to 1000 million.

ETIMEDOUT

Description: The mutex could not be locked before the specified timeout expired.

See the discussion in pthread_mutex_lock Return Values.

Destroying a Mutex

Use pthread_mutex_destroy(3C) to destroy any state that is associated with the mutex pointed to by mp .

pthread_mutex_destroy Syntax
int pthread_mutex_destroy(pthread_mutex_t *mp); 
#include <pthread.h>

pthread_mutex_t mp;
int ret;

ret = pthread_mutex_destroy(&mp); /* mutex is destroyed */

Note that the space for storing the mutex is not freed.

pthread_mutex_destroy Return Values

pthread_mutex_destroy() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occur, the function fails and returns the corresponding value.

EINVAL

Description: The value specified by mp does not refer to an initialized mutex object.

Code Examples of Mutex Locking

Example 4-1 shows some code fragments with mutex locking.

Example 4-1 Mutex Lock Example

#include <pthread.h>

pthread_mutex_t count_mutex;
long long count;

void
increment_count()
{
    pthread_mutex_lock(&count_mutex);
    count = count + 1;
    pthread_mutex_unlock(&count_mutex);
}

long long
get_count()
{
    long long c;
    
    pthread_mutex_lock(&count_mutex);
    c = count;
    pthread_mutex_unlock(&count_mutex);
    return (c);
}

The two functions in Example 4-1 use the mutex lock for different purposes. The increment_count() function uses the mutex lock to ensure an atomic update of the shared variable. The get_count() function uses the mutex lock to guarantee that the 64-bit quantity count is read atomically. On a 32-bit architecture, a long long is really two 32-bit quantities.

When you read an integer value, the operation is atomic because an integer is the common word size on most machines.

Examples of Using Lock Hierarchies

Occasionally, you might want to access two resources at once. Perhaps you are using one of the resources, and then discover that the other resource is needed as well. A problem exists if two threads attempt to claim both resources but lock the associated mutexes in different orders. For example, if the two threads lock mutexes 1 and 2 respectively, a deadlock occurs when each attempts to lock the other mutex. Example 4-2 shows possible deadlock scenarios.

Example 4-2 Deadlock

Thread 1
Thread 2
pthread_mutex_lock(&m1);

/* use resource 1 */


pthread_mutex_lock(&m2);


/* use resources 1 and 2 */


pthread_mutex_unlock(&m2);


pthread_mutex_unlock(&m1);
pthread_mutex_lock(&m2);

/* use resource 2 */


pthread_mutex_lock(&m1);


/* use resources 1 and 2 */


pthread_mutex_unlock(&m1);


pthread_mutex_unlock(&m2);

The best way to avoid this problem is to make sure that when threads lock multiple mutexes, the threads do so in the same order. When locks are always taken in a prescribed order, deadlock should not occur. This technique, known as lock hierarchies, orders the mutexes by logically assigning numbers to the mutexes.

Also, honor the restriction that you cannot take a mutex that is assigned n when you are holding any mutex assigned a number that is greater than n.

However, this technique cannot always be used. Sometimes, you must take the mutexes in an order other than prescribed. To prevent deadlock in such a situation, use pthread_mutex_trylock(). One thread must release its mutexes when the thread discovers that deadlock would otherwise be inevitable.

Example 4-3 Conditional Locking

thread1
thread2
pthread_mutex_lock(&m1); pthread_mutex_lock(&m2);

/* no processing */

pthread_mutex_unlock(&m2);

pthread_mutex_unlock(&m1);

for (; ;)

{ pthread_mutex_lock(&m2);

if(pthread_mutex_trylock(&m1)==0)

/* got it */

break;

/* didn't get it */

pthread_mutex_unlock(&m2);

}

/* get locks; no processing */

pthread_mutex_unlock(&m1);

pthread_mutex_unlock(&m2);

In Example 4-3, thread1 locks mutexes in the prescribed order, but thread2 takes the mutexes out of order. To make certain that no deadlock occurs, thread2 has to take mutex1 very carefully. If thread2 blocks while waiting for the mutex to be released, thread2 is likely to have just entered into a deadlock with thread1.

To ensure that thread2 does not enter into a deadlock, thread2 calls pthread_mutex_trylock(), which takes the mutex if available. If the mutex is not available, thread2 returns immediately, reporting failure. At this point, thread2 must release mutex2. Thread1 can now lock mutex2, and then release both mutex1 and mutex2.

Examples of Using Nested Locking With a Singly-Linked List

Example 4-4 and Example 4-5 show how to take three locks at once. Deadlock is prevented by taking the locks in a prescribed order.

Example 4-4 Singly-Linked List Structure

typedef struct node1 {
    int value;
    struct node1 *link;
    pthread_mutex_t lock;
} node1_t;

node1_t ListHead;

This example uses a singly linked list structure with each node that contains a mutex. To remove a node from the list, first search the list starting at ListHead until the desired node is found. ListHead is never removed.

To protect this search from the effects of concurrent deletions, lock each node before any of its contents are accessed. Because all searches start at ListHead, a deadlock cannot occur because the locks are always taken in list order.

When the desired node is found, lock both the node and its predecessor since the change involves both nodes. Because the predecessor's lock is always taken first, you are again protected from deadlock. Example 4-5 shows the C code to remove an item from a singly-linked list.

Example 4-5 Singly-Linked List With Nested Locking

node1_t *delete(int value)
{
    node1_t *prev, *current;

    prev = &ListHead;
    pthread_mutex_lock(&prev->lock);
    while ((current = prev->link) != NULL) {
        pthread_mutex_lock(&current->lock);
        if (current->value == value) {
            prev->link = current->link;
            pthread_mutex_unlock(&current->lock);
            pthread_mutex_unlock(&prev->lock);
            current->link = NULL;
            return(current);
        }
        pthread_mutex_unlock(&prev->lock);
        prev = current;
    }
    pthread_mutex_unlock(&prev->lock);
    return(NULL);
}
Example of Nested Locking With a Circularly-Linked List

Example 4-6 modifies the previous list structure by converting the list structure into a circular list. Because a distinguished head node no longer exists, a thread can be associated with a particular node and can perform operations on that node and its neighbor Lock hierarchies do not work easily here because the obvious hierarchy, following the links, is circular.

Example 4-6 Circular-Linked List Structure

typedef struct node2 {
    int value;
    struct node2 *link;
    pthread_mutex_t lock;
} node2_t;

Here is the C code that acquires the locks on two nodes and performs an operation that involves both locks.

Example 4-7 Circular Linked List With Nested Locking

void Hit Neighbor(node2_t *me) {
    while (1) {
        pthread_mutex_lock(&me->lock);
        if (pthread_mutex_trylock(&me->link->lock)!= 0) {
            /* failed to get lock */             
            pthread_mutex_unlock(&me->lock);              
            continue;         
        }         
        break;     
    }     
    me->link->value += me->value;     
    me->value /=2;     
    pthread_mutex_unlock(&me->link->lock);     
    pthread_mutex_unlock(&me->lock);
}