7/21/2017
Mutexes
• Threaded programs need to share data between
programs.
Thread Synchronization • Memory accesses to the same data are “mutually
exclusive.” (To avoid inconsistent state of data)
• Mutex provides direct programming support to
Harshad B. Prajapati handle mutual exclusive access.
Associate Professor
• Using mutex, a thread locks before entering critical
Information Technology Department,
section, and then the thread unlocks after exiting
Dharmsinh Desai University, Nadiad
from critical section.
Mutex characteristics Mutexes
• Mutex lock guarantees three things: • Mutex operation while three threads are
1. Atomicity - Locking a mutex is an atomic operation working simultaneously.
(no other thread succeeded in locking this mutex at
the same time)
2. Singularity - If a thread managed to lock a mutex, it is
assured that no other thread will be able to lock the
thread until the original thread releases the lock.
3. Non-Busy Wait – Other threads which could not
succeed in locking, will not consume any CPU
resource (i.e. no busy waiting).
Mutex: data types and functions Mutex: data types and functions
• Mutex: Create operation
• Mutex lock variable – int pthread_mutex_init(pthread_mutex_t *mutex,
pthread_mutexattr_t *attr);
–pthread_mutex_t mutex= • The pthread_mutex_init() function initializes the mutex referenced by
PTHREAD_MUTEX_INITIALIZER; mutex with attributes specified by attr.
• If attr is NULL, the default mutex attributes are used;
• This is a way of initializing mutex (lock) • Mutex: destroy operation
variable. – int pthread_mutex_destroy(pthread_mutex_t *mutex);
– The pthread_mutex_destroy() function destroys the mutex object
• The PTHREAD_MUTEX_INITIALIZER is a referenced by mutex;
constant defined in header file.
• Note: Generally, all functions return 0 on success and
error code on failure.
1
7/21/2017
Mutex: data types and functions Mutex: data types and functions
• Mutex: lock operation • Mutex: unlock operation
– int pthread_mutex_lock(pthread_mutex_t *mutex); – int pthread_mutex_unlock(pthread_mutex_t *mutex);
• The mutex object referenced by mutex is locked by calling pthread_mutex_lock(). • The pthread_mutex_unlock() function releases the mutex object referenced by
• If the mutex is already locked, the calling thread blocks until the mutex becomes mutex.
available.
• This operation returns with the mutex object referenced by mutex in the locked
state with the calling thread as its owner.
• Mutex: try-lock operation
– int pthread_mutex_trylock(pthread_mutex_t *mutex);
• It is identical to pthread_mutex_lock() except that if the mutex
object referenced by mutex is currently locked (by any thread,
including the current thread), the call returns immediately. (No
waiting)
Example: Producer-Consumer Example: Producer-Consumer
Problem Problem
#include <stdio.h> void* producer(void*); //producer thread function
#include <pthread.h> void* consumer(void*); //consumer thread function
#define MAXNITEMS 1000000 int min(int,int);
#define MAXNTHREADS 100
int main(int argc,char** argv){
int nitems; int i,nthreads,count[MAXNTHREADS];
struct{ pthread_t tid_produce[MAXNTHREADS],tid_consume;
pthread_mutex_t mutex;// mutex variable works as lock if(argc!=3){
int buff[MAXNITEMS];// shared buffer fprintf(stderr,"Usage : %s #items #threads\n",argv[0]);
int nput; //put pointer to shared buffer exit(-1);
int nval; //value to be put on shared buffer on nput index }
}shared={PTHREAD_MUTEX_INITIALIZER};
Example: Producer-Consumer Example: Producer-Consumer
Problem Problem
nitems=min(atoi(argv[1]),MAXNITEMS); /* start, then wait for consumer thread */
nthreads=min(atoi(argv[2]),MAXNTHREADS); pthread_create(&tid_consume,NULL,consumer,NULL);
/* start all producer threads */ pthread_join(tid_consume,NULL);
for(i=0;i<nthreads;i++){ exit(0);
count[i]=0; }
pthread_create(&tid_produce[i],NULL,producer,&count[i]);
}
/* wait for all producer threads */
for(i=0;i<nthreads;i++){
pthread_join(tid_produce[i],NULL);
printf("count[%d] = %d\n",i,count[i]);
}
2
7/21/2017
Example: Producer-Consumer Example: Producer-Consumer
Problem Problem
void* consumer(void* arg){ void * producer(void* arg){
int i=0; for(;;){
printf("-------CONSUMER STARTS--------\n"); // pthread_mutex_lock(&shared.mutex);
if(shared.nput>=nitems){
for(i=0;i<nitems;i++){ // pthread_mutex_unlock(&shared.mutex);
if(shared.buff[i]!=i) return NULL;
// if consumer finds any wrong value in buffer, just print it }
printf("buff[%d]=%d\n",i,shared.buff[i]); shared.buff[shared.nput]=shared.nval;
} shared.nput++;
printf("-------CONSUMER ENDS--------\n"); shared.nval++;
return NULL; // pthread_mutex_unlock(&shared.mutex);
} *((int*)arg)+=1;
}
}
Example: Producer-Consumer
Condition Variables
Problem
int min(int a,int b){ • Consider a situation
if(a<b)
– If a thread does not want to do any activity (wait) until it
return a;
gets some resources(or some state of resources); And
else
when this happens, the thread wants to get informed
return b;
(notify).
}
– The solution is “using condition variable”.
Condition Variables: mutex v/s
Condition Variables
condition variable
• A mutex • A condition variable is of type
– It provides mutual exclusion.
– It provides mutual exclusive (controlled) access to shared
– pthread_cond_t
data • Ex: pthread_cond_t
condv=PTHREAD_COND_INITIALIZER;
• while condition variable
– It allows threads to synchronize based upon the actual
value of data. – to initialize it during runtime, one must use the
– It provides a signaling mechanism. pthread_cond_init() function. (See man pages)
– Without condition variable, the threads need to
continuously wait for some condition. (It is called polling,
busy waiting, and it wastes CPU time)
3
7/21/2017
Condition Variables Condition Variables
• Functions • Functions
– int pthread_cond_wait(pthread_cond_t *cvptr, – int pthread_cond_timedwait(pthread_cond_t
pthread_mutex_t *mptr); *cond, pthread_mutex_t *mutex, const struct
• block on a condition variable timespec *abstime);
• It is called with mutex locked by the calling thread (or • It allows the programmer to specify a timeout for the
undefined behaviour will result.) waiting, after which the function always returns, with a
• It automatically and atomically does following proper error value.
– Unlocks (releases) mutex
– causes the calling thread to block on the condition variable
cond
• When, pthread_cond_wait returns, it locks the mutex.
Condition Variables Condition Variables
struct timeval tv; • int pthread_cond_signal(pthread_cond_t *
struct timespec ts; cptr);
If(gettimeofday(&tv,NULL)<0){
– This call unblocks at least one of the threads that
//error
are blocked on the specified condition variable
}
cond (if any threads are blocked on cond).
ts.tv_sec=tv.tv_sec+5; /* 5 seconds in future */
ts.tv_nsec=tv.tv_usec * 1000; /* micro to nano sec*/
– When a thread is signalled (wake up), mutex is
automatically and atomically locked.
pthread_cond_timedwait(…,&ts); • int pthread_cond_broadcast(pthread_cond_t
*cond);
– The call unblocks all threads currently blocked on
the specified condition variable cond.
Condition variable for synchronization
Condition Variables
(General structure of program)
• int pthread_cond_destroy(pthread_cond_t //part of a thread that wakes-up sleeping thread
*cond); struct{
– It destroies the given condition variable specified pthread_mutex_t mutex;
by cond (It frees any system resources it might be pthread_cond_t cond;
using.) variable_maintaing_condition_value
}var=//initialization code{…};
pthread_mutex_lock(&var.mutex);
Set condition true
pthread_cond_signal(&var.cond);
ptherad_mutex_unlock(&var.mutex);
4
7/21/2017
Condition variable for synchronization
Program
(General structure of program)
//part of a thread that sleeps until specified condition • proConMutexWCondV.c
occurs #include <stdio.h>
#include <pthread.h>
#define MAXNITEMS 1000000
pthread_mutex_lock(&var.mutex);
#define MAXNTHREADS 100
while(condition_is_false)
pthread_cond_wait(&var.cond); int nitems;
Modify condition int buff[MAXNITEMS];// shared buffer
ptherad_mutex_unlock(&var.mutex);
Program Program
/* mutex for synchronized access to buffer*/ void* producer(void*); //producer thread function
struct{ void* consumer(void*); //consumer thread function
pthread_mutex_t mutex;// mutex variable works as lock
int min(int,int);
int nput; //put pointer to shared buffer
int nval; //value to be put on shared buffer on nput index int main(int argc,char** argv){
}shared={PTHREAD_MUTEX_INITIALIZER}; int i,nthreads,count[MAXNTHREADS];
pthread_t tid_produce[MAXNTHREADS],tid_consume;
/* mutex for synchronized access to nready*/ if(argc!=3){
struct {
fprintf(stderr,"Usage : %s #items #threads\n",argv[0]);
pthread_mutex_t mutex;
pthread_cond_t cond; exit(-1);
int nready; }
}ready={PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER}; nitems=min(atoi(argv[1]),MAXNITEMS);
nthreads=min(atoi(argv[2]),MAXNTHREADS);
Program Program
/* Create all producer threads */ /* wait for all producer threads and cosumer thread */
for(i=0;i<nthreads;i++){ for(i=0;i<nthreads;i++){
count[i]=0; pthread_join(tid_produce[i],NULL);
printf("count[%d] = %d\n",i,count[i]);
pthread_create(&tid_produce[i],NULL,producer,&count[i }
]); pthread_join(tid_consume,NULL);
} exit(0);
/* Create one consumer thread */ }
pthread_create(&tid_consume,NULL,consumer,NULL);
5
7/21/2017
Program Program
void* consumer(void* arg){ if(buff[i]!=i)
int i=0; // if consumer finds any wrong value in buffer, just print it
for(i=0;i<nitems;i++){ printf("buff[%d]=%d\n",i,buff[i]);
pthread_mutex_lock(&ready.mutex); }
// go to sleep, if no new produced item is ready return NULL;
while(ready.nready==0) }
pthread_cond_wait(&ready.cond,&ready.mutex);
ready.nready--;
pthread_mutex_unlock(&ready.mutex);
Program Program
void * producer(void* arg){ pthread_mutex_lock(&ready.mutex);
for(;;){ //producer produced an item, awakens thread that are waiting
pthread_mutex_lock(&shared.mutex); for non-zero value of ready.nready
if(shared.nput>=nitems){ if(ready.nready==0)
pthread_mutex_unlock(&shared.mutex); pthread_cond_signal(&ready.cond);
return NULL; ready.nready++;
} pthread_mutex_unlock(&ready.mutex);
buff[shared.nput]=shared.nval; *((int*)arg)+=1;
shared.nput++; }
shared.nval++; }
pthread_mutex_unlock(&shared.mutex);
Program
int min(int a,int b){
if(a<b)
return a;
else
return b;
}