posix synchronization introduction to operating systems: discussion module 5
TRANSCRIPT
POSIX Synchronization
Introduction to Operating Systems: Discussion Module 5
POSIX Synchronization
Synchronization objects are variables in memory that you access just like data.
Threads in different processes can communicate with each other through synchronization objects placed in shared memory. Threads in different processes are generally invisible to each
other.
The available types of synchronization objects include: Mutex Locks Condition Variables
Steps in using a mutex
Initialize an attribute object Reset attribute settings
Can the mutex be shared across processes? Is there any deadlock protection?
Create a mutex using the attribute object Use the mutex
Lock, unlock, trylock Destroy the mutex
Attribute Initialization
int pthread_mutexattr_init(
pthread_mutexattr_t *mattr); Use pthread_mutexattr_init() to initialize
attributes associated with this object to their default values. Storage for each attribute object is allocated by the threads system during execution.
The default value of the pshared attribute when this function is called is PTHREAD_PROCESS_PRIVATE, which means that the initialized mutex can only be used within a process.
Mutex scope
int pthread_mutexattr_setpshared( pthread_mutexattr_t *mattr, int pshared);
The scope of a mutex variable can be either process private (intraprocess) or system wide (interprocess).
If the mutex is created with the pshared attribute set to the PTHREAD_PROCESS_SHARED state, and it exists in shared memory, it can be shared among threads from more than one process.
pshared can take one of two values: PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_SHARED
Mutex Type
int pthread_mutexattr_settype( pthread_mutexattr_t *attr , int type); pthread_mutexattr_settype() sets the mutex
type attribute. The type argument specifies the type of mutex. Valid mutex types include: PTHREAD_MUTEX_NORMAL
This type of mutex does not detect deadlock. A thread attempting to relock this mutex without first unlocking it will
deadlock. Attempting to unlock a mutex locked by a different thread results in
undefined behavior. Attempting to unlock an unlocked mutex results in undefined behavior.
Mutex Type
PTHREAD_MUTEX_ERRORCHECK This type of mutex provides error checking. A thread attempting to relock this mutex without first unlocking
it will return with an error. A thread attempting to unlock a mutex which another thread has
locked will return with an error. A thread attempting to unlock an unlocked mutex will return with
an error.
Mutex Type
PTHREAD_MUTEX_RECURSIVE A thread attempting to relock this mutex without first unlocking
it will succeed in locking the mutex. The relocking deadlock which can occur with mutexes of type PTHREAD_MUTEX_NORMAL cannot occur with this type of mutex.
Multiple locks of this mutex require the same number of unlocks to release the mutex before another thread can acquire the mutex.
A thread attempting to unlock a mutex which another thread has locked will return with an error.
A thread attempting to unlock an unlocked mutex will return with an error.
Mutex Type
PTHREAD_MUTEX_DEFAULT Attempting to recursively lock a mutex of this type results in
undefined behavior. Attempting to unlock a mutex of this type which was not locked
by the calling thread results in undefined behavior. Attempting to unlock a mutex of this type which is not locked
results in undefined behavior.
Attribute Destruction
int pthread_mutexattr_destroy(
pthread_mutexattr_t *mattr); Before a mutex attribute object can be reinitialized, it
must first be destroyed by a call to pthread_mutexattr_destroy().
If the object is not destroyed, a memory leak will result.
Initialize a Mutex
int pthread_mutex_init(
pthread_mutex_t *mp,
const pthread_mutexattr_t *mattr);
When the mutex is initialized, it is in an unlocked state A mutex lock must not be reinitialized or destroyed
while other threads might be using it. If a mutex is reinitialized or destroyed, the application
must be sure the mutex is not currently in use.
Lock a Mutex
int pthread_mutex_lock(
pthread_mutex_t *mutex);
Use pthread_mutex_lock() to lock the mutex pointed to by mutex.
When pthread_mutex_lock() returns, the mutex is locked and 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.
Unlock a Mutex
int pthread_mutex_unlock( pthread_mutex_t *mutex);
Use pthread_mutex_unlock() to unlock the mutex pointed to by mutex
pthread_mutex_unlock() releases the mutex object referenced by mutex
If there are threads blocked on the mutex object referenced by mutex when pthread_mutex_unlock()is called, the scheduling policy is used to determine which thread shall acquire the mutex.
Lock with a Nonblocking Mutex
int pthread_mutex_trylock( pthread_mutex_t *mutex);
Use pthread_mutex_trylock( ) to attempt to lock the mutex pointed to by mutex
pthread_mutex_trylock()is a non-blocking 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(EBUSY). Otherwise, the mutex is locked and the calling thread is the owner.
Destroy a Mutex
int pthread_mutex_destroy(
pthread_mutex_t *mutex); Use pthread_mutex_destroy( ) function
to destroy a previously initialized mutex The mutex can not be used after it has been
destroyed Note that the space for storing the mutex is not
freed
mutex.c #include <pthread.h>
#include <unistd.h>
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
static void *print_thread (void *param) { const char *name = param; int i; while (true) { pthread_mutex_lock(& print_lock); printf ("Hello "); printf ("from "); printf ("`%s' ", name); for (i = 'A'; i <= 'Z'; i++) printf ("%c", i); printf ("\r\n"); pthread_mutex_unlock(& print_lock); } return 0;}
mutex.c (continued)int main (void) {
pthread_t id;pthread_create (&id, NULL, print_thread, "Thread 1");pthread_create (&id, NULL, print_thread, "Thread 2");pthread_create (&id, NULL, print_thread, "Thread 3");pthread_create (&id, NULL, print_thread, "Thread 4");pthread_create (&id, NULL, print_thread, "Thread 5");pthread_create (&id, NULL, print_thread, "Thread 6");
while (1) {pthread_mutex_lock(& print_lock);printf ("sleep\r\n");pthread_mutex_unlock(& print_lock);sleep (1);
}return 0;
}
Condition Variables
A condition variable is used to wait until a particular condition is true like in a monitor
Always use condition variables together with a mutex lock The mutex provides the mutual exclusive aspect of a
monitor The attributes for condition variables must be set
and initialized before the condition variables can be used
Steps in using a condition variable
Create an attribute object Create a condition variable, associating it with an
existing mutex Use the condition variable
Wait, signal, broadcast Destroy the condition variable
Attribute Initialization
int threads_condattr_init( pthread_condattr_t *cattr);
The pthread_condattr_init() call returns a pointer to an opaque object
The possible values of cattr’s scope are PTHREAD_PROCESS_PRIVATE (the default) and PTHREAD_PROCESS_SHARED
If the object is not destroyed, a memory leak will result
Setting The Scope
int pthread_condattr_setpshared( pthread_condattr_t *cattr, int pshared);
pthread_condattr_setpshared( ) sets the scope of a condition variable to either process private(intraprocess) or system wide (interprocess)
PTHREAD_PROCESS_SHARED it can be shared among threads from more than one process
PTHREAD_PROCESS_PRIVATE (default value): only those threads created by the same process can operate on the object
Attribute Destruction
int pthread_condattr_destroy(
pthread_condattr_t *cattr); Use pthread_condattr_destroy( ) to
remove storage and render the object invalid The object must be reinitialized before it can be
reused
Initialize A Condition Variable
int pthread_cond_init(
pthread_cond_t *cv,
const pthread_condattr_t *cattr); Initializes the condition variable pointed at by cv to
its default value (cattr is NULL), or to specify condition variable attributes that are already set with pthread_condattr_init().
Wait On Condition Variable
int pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mp); Use pthread_cond_wait( ) to release the
mutex pointed to by mp and to cause the calling thread to block on the condition variable pointed to by cv
The blocked thread can be awakened by a pthread_cond_signal(), or a pthread_cond_broadcast()
Wait on Condition Variable
Unblock A Thread
int pthread_cond_signal( pthread_cond_t *cv); Use pthread_cond_signal( ) to unblock
one thread that is blocked on the condition variable pointed to by cv.
If more than one thread is blocked on a condition variable, the scheduling policy determines the order in which blocked threads are awakened.
For SCHED_OTHER, threads are awakened in priority order.
Condition Signal
BEEP
Unblock All Threads
Int pthread_cond_broadcast(
pthread_cond_t *cv); Use pthread_cond_broadcast( ) to unblock all
threads that are blocked on the condition variable pointed to by cv, specified by pthread_cond_wait().
When no threads are blocked on the condition variable, pthread_cond_broadcast() has no effect.
Condition Broadcast
SQUEAL
Destroy Condition Variable
int pthread_cond_destroy(
pthread_cond_t *cv); The pthread_cond_destroy() function
destroys a previously initialized condition variable The condition variable must not be used after it has
been destroyed. The space for storing the condition variable is not
freed.
condvar.c#include <pthread.h> #include <stdio.h> #define MAX 1000 #define MAX_COUNT 2000
int count = 0;pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t count_max = PTHREAD_COND_INITIALIZER; int thread_id[3] = {0,1,2};
void increment(void *); void watch(void *);
condvar.c
int main(int argc, char *argv[]) { int i; pthread_t thread[3]; pthread_create(&thread[0], NULL, increment, (void*)&thread_id[0]); pthread_create(&thread[1], NULL, increment, (void*)&thread_id[1]); pthread_create(&thread[2], NULL, watch, (void*)&thread_id[2]);
for(i=0; i< 3 ; i++) pthread_join(thread[i], NULL); return 0;}
condvar.c (continued)void watch(void* ID) { int* id = (int*)ID; pthread_mutex_lock(&count_mutex); while(count <= MAX_COUNT) { pthread_cond_wait(&count_max, &count_mutex); printf("Inside the watch() and the value is %d\n", count); } pthread_mutex_unlock(&count_mutex); }
condvar.c (continued)
void increment(void* ID) { int *id = (int*)ID; int i; for(i=0; i< MAX ; i++) { pthread_mutex_lock(&count_mutex); count++; printf("in increment counter by threadof id :%d, and count :%d\n",*id, count); pthread_cond_signal(&count_max); pthread_mutex_unlock(&count_mutex); } }
Compiling your C++ code with pthreads
You should use the g++ form of complier invocation
You must link with the pthread library g++ mycode.cpp -lpthread
Use cc or gcc to compile c code If you don’t include the link option, only your main
thread will execute! This works with Solaris; details vary from system
to system.