Part 2: Why we need Synchronization and how to achieve it?

Synchronization can be achieved by using any one of the following in Pthreads.
  • Mutex variables
  • Condition variables
  • Reader/Writer locks
We will discuss about the Mutex variable and Condition variables only.
Suppose the multiple threads share the common address space (thru a common variable), then there is a problem.
THREAD A                THREAD B
x = common_variable;    y = common_variable;
x++;                    y--;
common_variable =x      common_variable = y;

If threads execute this code independently it will lead to garbage. the access to the common_variable by both of them simultaneously is prevented by having a lock, performing the thing and then releasing the lock.

Mutex Variable

In Pthreads the locks are implemented using the "mutex" variable.
how to use MUTEX variables in Pthreads ?
  • Create and initialize a mutexfor each resource you want to protect, like common_variable in above example.
  • When the thread must access the resource, use pthread_mutex_lock to lock the resource's mutex.
  • When the thread is finished with the resource, unlock using the mutex by calling ptheread_mutex_unlock.
following code illustrates how it is done
/* initialising mutex variable in main program (statically) */

pthread_mutex_t com_mut_var = PTHREAD_MUTEX_INITIALIZER;
.
.


THREAD A                                 THREAD B
pthread_mutex_lock (&com_mut_var);      
                                         pthread_mutex_lock (&com_mut_var); 
a = common_variable;                             /* blocked */
a++;                                     /* blocked */
common_variable = a;                     /* blocked */
pthread_mutex_unlock(&com_mut_var);      /* blocked */
                                          b = common_variable;
                                          b--;
                                          common_variable = b;
                                          pthread_mutex_unlock (&com_mut_var);
Dynamic Initialization of Single Mutex Lock
In previous code the mutex variable was statically initialized, it can be initialized dynamically as follows
pthread_mutex_t *mut;
mut = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(mutexp, NULL);/* the attribute parameter is default because of NULL*/

Condition Variables

Mutex allows the threads to synchronize by controlling their access to data, whereas a condition variable allows to synchronize on the value of data. Condition variables notify the waiting threads. In absence of condition variables, threads would need to poll the variable to determine when it reaches a certain state.
As usual we will illustrate the use of the Condition variable through an example. We will have a global variable count which is protected by a mutex variable count_mutex. The main routine creates three threads. Two thread runs the increment routine and another thread starts the watch routine. The increment routine locks the variable, increases the count, prints it,if count has reached the max_value notifies the waiting thread, and unlocks the thread.The thread in watch routine waits on a condition variable using pthread_cond_wait. It suspends the caller until another thread notifys through the signal.To release threads that are waiting on a condition variable, a thread calls pthread_cond_signal or pthread_cond_broadcast.
#include <pthread.h>
#include <stdio.h>
#define MAX 1000
#define MAX_COUNT 1500
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(int *);
void watch(int *);
int
main(int argc, char *argv[])
{
int i;
/* define the type to be pthread */
pthread_t thread[3];
/* create 3 threads*/
pthread_create(&thread[0], NULL, increment, &thread_id[0]);
pthread_create(&thread[1], NULL, increment, &thread_id[1]);
pthread_create(&thread[2], NULL, watch, &thread_id[2]);
for(i=0; i< 3 ; i++)
{
pthread_join(thread[i], NULL);
}
return 0;
}
void watch(int *id)
{
/* lock the variable */
pthread_mutex_lock(&count_mutex);
while(count <= MAX_COUNT)
{
/* using the condition variable for waiting for the event */
pthread_cond_wait(&count_max, &count_mutex);
printf("Inside the watch() and the value is %d\n", count);
}
/*unlock the variable*/
pthread_mutex_unlock(&count_mutex);
}
void increment(int *id)
{
int i;
for(i=0; i< MAX ; i++)
{
/* lock the variable */
pthread_mutex_lock(&count_mutex);
count++;
printf("in increment counter by threadof id :%d, and count"
":%d\n",*id, count);
/* for the condition notify the thread */
pthread_cond_signal(&count_max);
/*unlock the variable*/
pthread_mutex_unlock(&count_mutex);
}
}

 

These examples just illustrate the basic working principle based on which any thread/synchronization based applications can be built.