Although the locking mechanisms used in Solaris are available to user-level threads as well as kernel threads, basically the synchronization methods discussed thus far pertain to synchronization within the kernel. In contrast, the Pthreads API is available for programmers at the user level and is not part of any particular kernel. This API provides mutex locks, condition variables, and read–write locks for thread synchronization.
Mutex locks represent the fundamental synchronization technique used
with Pthreads. A mutex lock is used to protect critical sections of code—that
is, a thread acquires the lock before entering a critical section and releases it
upon exiting the critical section. Pthreads uses the pthread mutex t data type
for mutex locks. A mutex is created with the pthread mutex init() function.
The first parameter is a pointer to the mutex. By passing NULL as a second
parameter, we initialize the mutex to its default attributes. This is illustrated
#include <pthread.h> pthread mutex t mutex; /* create the mutex lock */ pthread mutex init(&mutex,NULL);
The mutex is acquired and released with the pthread mutex lock() and pthread mutex unlock() functions. If the mutex lock is unavailable when pthread mutex lock() is invoked, the calling thread is blocked until the owner invokes pthread mutex unlock(). The following code illustrates protecting a critical section with mutex locks:
/* acquire the mutex lock */ pthread mutex lock(&mutex); /* critical section */ /* release the mutex lock */ pthread mutex unlock(&mutex);
All mutex functions return a value of 0 with correct operation; if an error occurs, these functions return a nonzero error code
Many systems that implement Pthreads also provide semaphores, although semaphores are not part of the Pthreads standard and instead belong to the POSIX SEM extension. POSIX specifies two types of semaphores—named and unnamed. The fundamental distinction between the two is that a named semaphore has an actual name in the file system and can be shared by multiple unrelated processes. Unnamed semaphores can be used only by threads belonging to the same process. In this section, we describe unnamed semaphores.
The code below illustrates the sem_init() function for creating and initializing an unnamed semaphore:
#include <semaphore.h> sem t sem; /* Create the semaphore and initialize it to 1 */ sem init(&sem, 0, 1);
The sem init() function is passed three parameters:
- A pointer to the semaphore
- A flag indicating the level of sharing
- The semaphore’s initial value