Now that we have learnt about semaphores and mutexes, let us write programs using these for the classical IPC problems. I give solution to one version(either using semaphores or using mutexes) per problem. The other versions for each problem is left as an exercise for the reader;).
I will be giving solutions to 4 different problems.
Producer Consumer ProblemDining Philosophers problem
Sleeping Barber problem
Readers-Writers problem
Note: I will be using the functions which I have provided in my previous post, for semaphores, which is in the file "mysem.c".
Producer-Consumer Problem:Semaphore Version
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<pthread.h>
#include "mysem.c"
#define MAX_BUF 10
int *buffer;
int head=0,tail=0,item_id=1;
int count=0;
int sem_ID; // 3 semaphores... { Mutex, Empty, Full}
int fflag=0,eflag=0;
void producer()
{
printf("Producer started\n");
while(1)
{
int v=0;
sem_change(sem_ID, 0, -1);
if(count==MAX_BUF)
{
printf("Producer waiting\n");
fflag=1;
sem_change(sem_ID, 0, 1);
sem_change(sem_ID, 2, -1);
sem_change(sem_ID, 0, -1); //Waits until a free slot is available
}
count++;
buffer[head]=item_id++;
if(count==1 && eflag==1)
{
eflag=0;
sem_change(sem_ID, 1, 1); //To signal consumer thread that buffer is not empty
}
printf("produced item:%d \n", buffer[head]);
head=(head+1)%MAX_BUF;
sem_change(sem_ID, 0, 1);
sleep(rand()%3);
}
}
void consumer()
{
printf("consumer started\n");
while(1)
{
int v=0;
sem_change(sem_ID, 0, -1);
if(count==0)
{
printf("Consumer Waiting\n");
eflag=1;
sem_change(sem_ID, 0, 1);
sem_change(sem_ID, 1, -1);
sem_change(sem_ID, 0, -1);
//Waits until an item is produced
}
count--;
printf("consumed item:%d \n", buffer[tail]);
tail=(tail+1)%MAX_BUF;
if(count==MAX_BUF-1 && fflag==1)
{
fflag=0;
sem_change(sem_ID, 2, 1); //To signal the producer thread that
}
buffer is not full
sem_change(sem_ID, 0, 1);
sleep(rand()%4);
}
}
int main()
{
buffer=(int*)calloc(MAX_BUF,sizeof(int));
pthread_t pro,con;
int values[]={1,0,0};
sem_ID=sem_init_diff_val(3, values); //initialize with 1, 0, 0
pthread_create(&pro, NULL, (void*)&producer, NULL);
pthread_create(&con, NULL, (void*)&consumer, NULL);
pthread_join(pro,NULL);
return 0;
}
Dining Philosophers Problem:Mutex Version
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define PHILOSOPHERS 5
pthread_mutex_t spoon[PHILOSOPHERS];
//Intializes the philosopher threads
void phil_init(int a, int* b, int* c)
{
*b=(a>0) ? a-1 : PHILOSOPHERS;
*c=a;
printf("Philosopher %d started\n", a+1);
return;
}
int check_If_Spoons_Are_Available(int a, int b, int c)
{
int sum=0;
if(a&1)
{
sum = pthread_mutex_trylock(&spoon[c])==0 ? 0 : 10;
sum += pthread_mutex_trylock(&spoon[b])==0 ? 0 : 1;
}
else
{
sum = pthread_mutex_trylock(&spoon[b])==0 ? 0 : 1;
sum += pthread_mutex_trylock(&spoon[c])==0 ? 0 : 10;
}
return sum;
}
void Release_Spoons(int a, int b, int c)
{
if(a&1)
{
pthread_mutex_unlock(&spoon[b]);
pthread_mutex_unlock(&spoon[c]);
}
else
{
pthread_mutex_unlock(&spoon[c]);
pthread_mutex_unlock(&spoon[b]);
}
}
void wait_for_others_to_finish(int a, int b ,int c, int d)
{
switch(a)
{
case 1:
printf("Philosopher %d waiting since right spoon is unavailable\n",b+1);
pthread_mutex_lock(&spoon[c]);
break;
case 10:
printf("Philosopher %d waiting since left spoon is unavailable\n", b+1);
pthread_mutex_lock(&spoon[d]);
break;
case 11:
printf("Philosopher %d waiting since both spoons are unavailable\n", b+1);
if(a&1)
{
pthread_mutex_lock(&spoon[d]);
pthread_mutex_lock(&spoon[c]);
}
else
{
pthread_mutex_lock(&spoon[d]);
pthread_mutex_lock(&spoon[c]);
}
break;
}
return;
}
void Eat(int a)
{
printf("philosopher %d eating\n", a+1);
sleep(rand()%5);
printf("philosopher %d finished eating\n", a+1);
}
void philo(void * arg)
{
int back;
int front;
int tmp;
int id=*((int*)arg);
phil_init(id, &back, &front);
while(1)
{
printf("philosopher %d thinking\n", id+1);
sleep(rand()%6);
if((tmp=check_If_Spoons_Are_Available(id, back, front))!=0)
wait_for_others_to_finish(tmp, id, back, front);
Eat(id);
Release_Spoons(*((int*)arg), back, front);
}
}
int main(int argc, char* argv[])
{
pthread_t S[PHILOSOPHERS];
int *g;
for(int i=0; i<PHILOSOPHERS; i++)
pthread_mutex_init(&spoon[i], NULL);
g=(int*)malloc(PHILOSOPHERS*sizeof(int));
for(int i=0; i<PHILOSOPHERS; i++)
{
g[i]=i;
pthread_create(&S[i], NULL, (void*)&philo,(void*)&g[i]);
}
pthread_join(S[0], NULL);
exit(0);
}
Sleeping Barber Problem:Semaphore Version
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include "mysem.c"
#define MAX_C 5
int sem_ID; //----> creates a set of 5 semaphores. { mutex, cond_empty, counting semaphore, waiting semaphore, barber semaphore}
int customers_count=0;
int eflag=fflag=0;
void barber()
{
printf("barber started\n");
while(1)
{
sem_change(sem_ID, 0, -1);
if(customers_count==0)
{
printf("barber sleeping\n");
eflag=1;
sem_change(sem_ID, 0, 1);
sem_change(sem_ID, 1, -1);
sem_change(sem_ID, 0, -1);
}
customers_count--;
sem_change(sem_ID, 0, 1);
sem_change(sem_ID, 3, 1);
// printf("tail:%d\n", tail);
// pthread_mutex_lock(&B);
sem_change(sem_ID, 4, -1);
// pthread_mutex_unlock(&B);
}
}
void customer(void *arg)
{
//printf("C\n");
sem_change(sem_ID, 0, -1);
if(customers_count==MAX_C) // If all seats are occupied exit the thread
{
int *ptr=(int*)arg;
*ptr=0;
printf("No place for customer %d so leaving\n", pthread_self());
sem_change(sem_ID, 0, 1);
return;
}
customers_count++;
if(customers_count==1 && eflag==1)
{
sem_change(sem_ID, 1, 1);
eflag=0;
}
sem_change(sem_ID, 0, 1);
printf("Customer %d got a place\n", pthread_self());
sem_change(sem_ID, 3, -1);
printf("Cutting for %d customer\n", pthread_self());
sleep(rand()%5+4);
sem_change(sem_ID, 4, 1);
// printf("head:%d\n", head);
// pthread_mutex_lock(&B);
// pthread_mutex_unlock(&B);
int *ptr=(int*)arg;
*ptr=0;
}
int main(int argc, char* argv[])
{
pthread_t barber_thread;
int live_threads[MAX_C+2]; // 0 = no thread is created with this index,
// 1=there is a live thread with this index
pthread_t customer_thread[MAX_C +2];
for(int i=0; i<MAX_C+2; i++)
live_threads[i]=0; // initially all are dead state
int array[]={1, 0, MAX_C, 0, 0}; // Initial values of different semaphores
sem_ID=sem_init_diff_val(5,array);
pthread_create(&barber_thread, NULL, (void*)&barber, NULL);
sleep(2);
//Continuous thread generator....
while(1)
{
for(int i=0; i<MAX_C+2; i++)
{
if(live_threads[i]==0)
{
live_threads[i]=1;
pthread_create(&customer_thread[i], NULL, (void*)&customer, (void*)&live_threads[i]);
sleep(rand()%4);
}
}
}
exit(0);
}
Readers Writers Problem:Mutex Version
Note: The execution depends on the selection algorithm of the mutex.
#include<stdio.h>
#include<pthread.h>
pthread_mutex_t no_wait, no_acc, counter;
int no_of_readers=0;
void reader(void *arg)
{
int id=*((int*)arg);
printf("reader %d started\n", id);
while(1)
{
sleep(rand()%4);
check_and_wait(id);
read(id);
}
}
void writer(void* arg)
{
int id=*((int*)arg);
printf("writer %d started\n", id);
while(1)
{
sleep(rand()%5);
check_and_wait_if_busy(id);
write(id);
}
}
/*sub functions for reader and writer threads*/
void check_and_wait_if_busy(int id)
{
if(pthread_mutex_trylock(&no_wait)!=0){
printf("Writer %d Waiting\n", id);
pthread_mutex_lock(&no_wait);
}
}
void check_and_wait(int id)
{
if(pthread_mutex_trylock(&no_wait)!=0){
printf("Reader %d Waiting\n", id);
pthread_mutex_lock(&no_wait);
}
}
void read(int id)
{
pthread_mutex_lock(&counter);
no_of_readers++;
pthread_mutex_unlock(&counter);
if(no_of_readers==1)
pthread_mutex_lock(&no_acc);
pthread_mutex_unlock(&no_wait);
printf("reader %d reading...\n", id);
sleep(rand()%5);
printf("reader %d finished reading\n", id);
pthread_mutex_lock(&counter);
no_of_readers--;
pthread_mutex_unlock(&counter);
if(no_of_readers==0)
pthread_mutex_unlock(&no_acc);
}
void write(int id)
{
pthread_mutex_lock(&no_acc);
pthread_mutex_unlock(&no_wait);
printf("Writer %d writing...\n", id);
sleep(rand()%4+2);
printf("Writer %d finished writing\n", id);
pthread_mutex_unlock(&no_acc);
}
/**************************************************/
//MAIN
int main(int argc, char* argv[])
{
pthread_t R[5],W[5];
int ids[5];
for(int i=0; i<5; i++)
{
ids[i]=i+1;
pthread_create(&R[i], NULL, (void*)&reader, (void*)&ids[i]);
pthread_create(&W[i], NULL, (void*)&writer, (void*)&ids[i]);
}
pthread_join(R[0], NULL);
exit(0);
}
<<Prev
Next>>
void wait_for_others_to_finish(int a, int b ,int c, int d)
ReplyDelete{
switch(a)
{
case 1:
printf("Philosopher %d waiting since right spoon is unavailable\n",b+1);
pthread_mutex_lock(&spoon[c]);
break;
case 10:
printf("Philosopher %d waiting since left spoon is unavailable\n", b+1);
pthread_mutex_lock(&spoon[d]);
break;
case 11:
printf("Philosopher %d waiting since both spoons are unavailable\n", b+1);
if(a&1)
{
pthread_mutex_lock(&spoon[d]);
pthread_mutex_lock(&spoon[c]);
}
else
{
pthread_mutex_lock(&spoon[d]);
pthread_mutex_lock(&spoon[c]);
}
break;
}
return;
}
what is the use of passing b as an argument in this function??
in last part for both a even and odd code is same.is'nt wrong??
I think, inside 'case 11:' block instead of if(a&1) it should be if(b&1) as the order of locking the spoons is dependent on id of the philosopher. Whereas 'a' is just a flag used to check which spoons were unavailable.
Delete