I am trying to create a simple bar program where a certain amount of customers can be inside the bar at the same time. And every time a customer asks for a beer, then the bartender should server the customer a beer.
For some reason in my program, the bar tender serves the customer after he/she leaves the bar
How can I fix this? Any suggestions?
Here is my code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> //for declaration of exit()
#include <semaphore.h> //to use semaphores
pthread_mutex_t serve = PTHREAD_MUTEX_INITIALIZER;
pthread_barrier_t barrier1;
sem_t OktoEnter;
int cid = 0;
void EnterBar();
void OrderStart();
void ServeStart();
void ServeDone();
void OrderDone();
void DrinkBeer();
void LeaveBar();
void* Bartender(void *arg)
{
ServeStart();
ServeDone();
}
void* Customer(void* id)
{
cid =(int)id;
EnterBar();
LeaveBar();
}
void EnterBar(){
printf("Customer %d enters the bar.\n", cid);
int cups;
pthread_t order;
for(cups=0;cups<(cid%3+1);cups++){
pthread_mutex_lock(&serve);
OrderStart();
OrderDone();
DrinkBeer();
pthread_mutex_unlock(&serve);
}
//decrease semaphore
}
void OrderStart(){
pthread_t order;
printf("Customer %d asks for beer.\n", cid);
int rc = pthread_create(&order, NULL, Bartender, NULL);
}
void OrderDone(){
printf("Customer %d gets the beer.\n", cid);
}
void DrinkBeer(){
printf("Customer %d drinks the beer.\n", cid);
}
void LeaveBar(){
printf("Customer %d leaves the bar.\n", cid);
//increase semaphore
}
void ServeStart(){
printf("Bartender starts to serve customer %d.\n", cid);
}
void ServeDone(){
printf("Bartender is done serving customer %d.\n", cid);
}
int main (int argc, char *argv[])
{
int t;
long rc;
int num_customers = atoi(argv[1]); //number of customers
int capacity = atoi(argv[2]); //bar capacity
if(num_customers > 0 && capacity > 0){
pthread_t threads[num_customers];
if(random() > RAND_MAX / 2)
usleep(1);
//rc = sem_init(&sem1,0,capacity);
rc = pthread_barrier_init(&barrier1, NULL, num_customers);
for(t=0; t< num_customers; t++){
printf("In main: creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, Customer, (void* )t);
if (rc){
printf("ERROR; return code from pthread_create() is %ld\n", rc);
exit(-1);
}
}
}
else{
printf("ERROR: Both parameters should be a valid positive numbers.");
exit(-1);
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
I worked all around changing the functions but it does not work properly.
To be honest it is not clear if you originally had a clear idea of where you were going with this to begin with or just got so lost in the weeds you started throwing things against the wall to see what would stick. Sorry for the mixed metaphors.
You had a bunch of small errors (e.g. sometimes cid was a param, sometimes it was a global shared by all threads) and a bunch of unnecessary stuff I assume was detritus from experimenting.
I stripped this down a very basic threaded program and I'll leave it at that since I really don't understand where exactly you want to take it. Get the simple stuff working first, layer on the complexity later. Good luck.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void EnterBar();
void OrderStart();
void ServeStart();
void ServeDone();
void OrderDone();
void DrinkBeer();
void LeaveBar();
void Bartender(int cid)
{
ServeStart(cid);
ServeDone(cid);
}
void* Customer(void* id)
{
int cid = (int) id;
EnterBar(cid);
LeaveBar(cid);
}
void EnterBar(int cid)
{
printf("Customer %d enters the bar.\n", cid);
int cups;
pthread_t order;
OrderStart(cid);
OrderDone(cid);
DrinkBeer(cid);
}
void OrderStart(int cid)
{
printf("Customer %d asks for beer.\n", cid);
Bartender(cid);
}
void OrderDone(int cid)
{
printf("Customer %d gets the beer.\n", cid);
}
void DrinkBeer(int cid)
{
printf("Customer %d drinks the beer.\n", cid);
}
void LeaveBar(int cid)
{
printf("Customer %d leaves the bar.\n", cid);
}
void ServeStart(int cid)
{
printf("Bartender starts to serve customer %d.\n", cid);
}
void ServeDone(int cid)
{
printf("Bartender is done serving customer %d.\n", cid);
}
int main (int argc, char *argv[])
{
int t;
long rc;
if (argc < 3)
{
printf("use the parameters\n");
exit(1);
}
int num_customers = atoi(argv[1]); //number of customers
int capacity = atoi(argv[2]); //bar capacity
if (num_customers <= 0 || capacity <= 0)
{
printf("ERROR: Both parameters should be a valid positive numbers.");
exit(1);
}
pthread_t threads[num_customers];
for (t = 0; t < num_customers; t++)
{
printf("In main: creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, Customer, (void* )t);
if (rc)
{
printf("ERROR; return code from pthread_create() is %ld\n", rc);
exit(1);
}
}
for (t = 0; t < num_customers; t++)
pthread_join(threads[t], NULL);
pthread_exit(NULL);
}
First, this is a great little project in understanding threads and how life is multi-threaded.
There are problems with the above scenarios. First off, neither of you are keeping track of how many customers are in the bar from your EnterBar() and LeaveBar() functions. In these functions, you will need to keep track of the current bar count. Once the bar is full, you must lock the door so no other customers can enter. Then when a customer leaves the bar, they must unlock the door so at least one more customer can enter. Also, given the complete problem scenario, you should only create one bartender (i.e. one bartender thread) and syncronize with him using pthread_cond_wait/pthread_cond_signal to pour the beer once a customer asks for it. You can't just keep killing off and recreating the bartender for each drink to be poured, and remember only one customer can ask for a beer at a time. This should all be done with pthread_mutex_lock/unlock's.
Related
I am trying to make a "guess the number" minigame to get used to pthreads and synchronization. A thread sleeps for 10 seconds, while the other reads input and says whether the number is too big or too low. When the first thread "wakes up", the second thread should no longer read input, regardless if it were executing scanf. When the second thread has read the correct number, the first thread should no longer sleep and ignore the rest of its code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
unsigned short quit = 0;
unsigned short won = 0;
void * engine(void * arg);
void * arbiter();
int main(int argc, char** argv) {
int n = rand() % 100;
pthread_t t1, t2;
pthread_create(&t1, NULL, arbiter, NULL);
pthread_create(&t2, NULL, engine, &n);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return (EXIT_SUCCESS);
}
void * arbiter(){
sleep(10);
quit = 1;
printf("Stop!\n");
}
void * engine(void * arg){
int n = *(int*)arg;
printf("%d\n", n);
while(!quit){
printf("N = ");
int a;
scanf("%d", &a);
if(a < n){
printf("Go higher!\n");
} else if(a > n){
printf("Go lower!\n");
} else{
printf("Bingo!\n");
won = 1;
}
}
}
I don't know how to use mutexes or cond var here, to make the threads work together. Now, when the first thread wakes up, the second will execute the last scanf. How should I implement this correctly and safe?
So I have been all day working on this project, I was checking the errors that I have and as I was fixing them I came to the last part which is the warnings.
the warnings that I am getting are the same: Passing argument 1 of '' from compatible pointer type [enabled by default]
note: expected 'union sem_t*' but argument is of type 'void * ()(void)'
please just help me out. I have been stuck on this for several hours now. thanks in advance!
I took off the & from sem_init in both customers and barbers, but it did not work.
#include <unistd.h> //Provides API for POSIX(or UNIX) OS for system calls
#include <stdio.h> //Standard I/O Routines
#include <stdlib.h> //For exit() and rand()
#include <pthread.h> //Threading APIs
#include <semaphore.h> //Semaphore APIs
#define MAX 30 //Maximum no. of customers for simulation
#define MAX_BARBERS 1000
sem_t customer; //Semaphore
sem_t barber; //Semaphore
sem_t mutex; //Semaphore for providing mutially exclusive access
void *barbers(void *param); //Thread Function
void *customers(void *param); //Thread Function
int num_chairs;
int barbers_total;
int customers_total;
int serveMeNext; //Index to choose a candidate for cutting hair
void wait(); //Randomized delay function
int main(int argc, char *argv[]){
pthread_t barberid[MAX_BARBERS];
pthread_t customerid[MAX]; //Thread declaration
int i = 0;
if(argc != 4){
printf("Enter 3 arguments (Number of chairs, barbers, customers)\n");
exit(0);
}
num_chairs = atoi(argv[1]);
barbers_total = atoi(argv[2]);
customers_total = atoi(argv[3]);
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
/*Semaphore initialization*/
sem_init(&mutex,0,1);
sem_init(customers,0,0);
sem_init(barbers,0,0);
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
/*Barber thread initialization*/
printf("!!Barber Shop Opens!!\n");
for(i = 0; i <= barbers_total; i++){ //Creation of barbers
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
pthread_create(&barberid[i], NULL, barbers, (void*)&i);
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
sleep(1);
}
/*Customer thread initialization*/
for(i = 0; i <= customers_total; i++){ //Creation of Customer Threads
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
pthread_create(&customerid[i],NULL,customers,(void*)&i);
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
wait(); //Create customers in random interval
}
for(i = 0; i <= MAX; i++) //Waiting till all customers are dealt with
pthread_join(customerid[i],NULL);
printf("!!Barber Shop Closes!!\n");
exit(EXIT_SUCCESS); //Exit abandoning infinite loop of barber thread
}
void *customers(void *param){ /*Customer Process*/
int mySeat, B;
static int count = 0; //Counter of No. of customers
int numberOfFreeSeats = num_chairs; //Counter for Vacant seats in waiting room
int seatPocket[num_chairs]; //To exchange pid between customer and barber
int sitHereNext = 0; //Index for next legitimate seat
serveMeNext = 0;
sem_wait(&mutex); //Lock mutex to protect seat changes
count++; //Arrival of customer
printf("Customer-%d entered shop. ",count);
if(numberOfFreeSeats > 0){
--numberOfFreeSeats; //Sit on chairs on waiting room
printf("Customer-%d Sits In Waiting Room.\n",count);
sitHereNext = (++sitHereNext) % num_chairs; //Choose a vacant chair to sit
mySeat = sitHereNext;
seatPocket[mySeat] = count;
sem_post(&mutex); //Release the seat change mutex
sem_post(barbers); //Wake up one barber
sem_wait(customers); //Join queue of sleeping customers
sem_wait(&mutex); //Lock mutex to protect seat changes
B = seatPocket[mySeat]; //Barber replaces customer PID with his own PID
numberOfFreeSeats++; //Stand Up and Go to Barber Room
sem_post(&mutex); //Release the seat change mutex
/*Customer is having hair cut by barber 'B'*/
}else{
sem_post(&mutex); //Release the mutex and customer leaves without haircut
printf("Customer-%d Finds No Seat & Leaves.\n",count);
}
pthread_exit(0);
}
void *barbers(void *param){ /*Barber Process*/
int index = *(int *)(param);
int myNext, C;
int worktime;
int seatPocket[num_chairs]; //To exchange pid between customer and barber
printf("Barber-%d joins shop. ",index);
while(1){ /*Infinite loop*/
printf("Barber-%d Gone To Sleep.\n",index);
sem_wait(barbers); //Join queue of sleeping barbers
sem_wait(&mutex); //Lock mutex to protect seat changes
serveMeNext = (++serveMeNext) % MAX; //Select next customermyNext = serveMeNext;
C = seatPocket[myNext]; //Get selected customer's PID
seatPocket[myNext] = pthread_self(); //Leave own PID for customer
sem_post(&mutex);
sem_post(customers); //Call selected customer
/*Barber is cutting hair of customer 'C'*/
printf("Barber-%d Wakes Up & Is Cutting Hair Of Customer-%d.\n",index,C);
worktime = (rand() % 3) + 1;
printf("Barber-%d Finished.\n",index);
sleep(worktime);
}
}
void wait(){ /*Generates random number between 50000 to 250000*/
int x = rand() % (250000 - 50000 + 1) + 50000;
srand(time(NULL));
usleep(x); //usleep halts execution in specified miliseconds
}
I marked with """ the places where I think I am wrong because of the research that I have been doing.
From the warning, it is evident that you were passing a pointer to a function instead of the sem_t type that it expects.
You seem to have had a typo with customer and barber.
The sem_init must be
sem_init(&customer,0,0);
sem_init(&barber,0,0);
And your sem_post must be
sem_post(&customer);
sem_post(&barber);
Also, don't forget to compile this with -lpthread or -pthread
I am writing a c program to create three threads(1,2,3) such that at any given point of time only one thread must execute and print the output on console in the order 123123123123.........
I am making use of semaphore for synchronization.
I am having an issue with the code i have written. the code doesn't print it in the order 123123... the order is random and stops after a while.
#include<stdio.h>
#include<semaphore.h>
#include<pthread.h>
#include<unistd.h>
#include<assert.h>
#include<stdlib.h>
sem_t sem_1;
void *func1(void *arg){
int err1=0;
while(1){
err1=sem_wait(&sem_1);
assert(err1==0);
printf("thread 1\n");
}
//return NULL;
}
void *func2(void *arg){
int err2=0;
while(1){
err2=sem_wait(&sem_1);
assert(err2==0);
printf("thread 2\n");
}
// return NULL;
}
void *func3(void *arg){
int err3=0;
while(1){
err3=sem_wait(&sem_1);
assert(err3==0);
printf("thread 3\n");
}
// return NULL;
}
int main(){
pthread_t *t1,*t2,*t3;
int i=0,rc=0,c1=0,c2=0,c3=0;
t1=(pthread_t *)malloc(sizeof(*t1));
t2=(pthread_t *)malloc(sizeof(*t2));
t3=(pthread_t *)malloc(sizeof(*t3));
i=sem_init(&sem_1,0,1);
assert(i==0);
c1=pthread_create(t1,NULL,func1,NULL);
assert(c1==0);
c2=pthread_create(t2,NULL,func2,NULL);
assert(c2==0);
c3=pthread_create(t3,NULL,func3,NULL);
assert(c3==0);
while(1){
rc=sem_post(&sem_1);
assert(rc==0);
sleep(1);
}
return 0;
}
Why would you even expect them in in an order?
Your threads do things inbetween the different waits, and according to the system scheduler, these can take different amount of time.
printf is a buffered operation that gives you exclusive access to a shared resource. So in addition to your semaphore there is a hidden lock somewhere, that also regulates the progress of your threads. Don't expect the prints to appear in order, even if the calls themselves are.
Then, for the end, using assert here is really a very bad idea. All sem_t operations can (and will) fail spuriously, so it is really bad to abort, just because such a failure.
In fact, sem_t is really a low level tool, and you should never use it without checking return values and without having a fall back strategy if such a call fails.
Of course. I can't see any order related synchronization mechanism.
One of the options to achieve the strict order is to have one semaphore per thread:
sem_t sem[3];
// ...
while(1) {
for(n = 0; n < 3; n++) {
rc=sem_post(&sem[n]);
assert(rc==0);
}
sleep(1);
}
Below Code will help to solve the problem, one semaphore for each thread used to achieve synchronization. The initial value of the semaphore does the job. used usleep to launch thread in sequence manner for needed output. The same can be done by using Mutex lock and cond variables
//declaring semaphore
sem_t sema1;
sem_t sema2;
sem_t sema3;
void* t1(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema1);
printf("Thread 1 \n");
sem_post(&sema2);
}
printf("T1 return\n");
return NULL;
}
void* t2(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema2);
printf("Thread 2 \n");
sem_post(&sema3);
}
printf("T2 return\n");
return NULL;
}
void* t3(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema3);
printf("Thread 3 \n");
sem_post(&sema1);
}
printf("T3 return \n");
return NULL;
}
int main()
{
pthread_t tid1, tid2,tid3;
sem_init(&sema1,0,1);
sem_init(&sema2,0,0);
sem_init(&sema3,0,0);
pthread_create(&tid1, NULL, t1, NULL);
usleep(100);
pthread_create(&tid2, NULL, t2, NULL);
usleep(100);
pthread_create(&tid3, NULL, t3, NULL);
pthread_join(tid3, NULL);
pthread_join(tid2, NULL);
pthread_join(tid1, NULL);
sem_destroy(&sema1);
sem_destroy(&sema2);
sem_destroy(&sema3);
return 0;
}
I'm working on an exercise (see bold text below) on semaphores and synchronization for my Operative System course. The text of the exercise is this:
Pthread semaphores and mutexes
The C program gen_binary_numbers.c receives on the command line an integer n, and uses recursion to generate and display all binary numbers of n bits.Transform the recursive program into a concurrent one, replacing the recursive procedure with the generation of an appropriate number of processes that display the binary numbers (in any order).
This is my code, actually:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
exit(EXIT_FAILURE);
}
int i;
num = atoi(argv[1]);
c = num;
r = 2;
for (i=1; i<num; i++) {
r=r*2;
}
pthread_mutex_init(&mutex, NULL);
pthread_t* p;
p = malloc(r*sizeof(pthread_t));
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &i)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
pthread_exit(0);
}
void *genBin (void *arg) {
int x;
int i=0;
x = *((int*)arg);
pthread_mutex_lock(&mutex);
while (i<num) {
if(x!=0) {
fprintf(stdout, "%d", x%2);
}
else {
fprintf(stdout, "0");
}
i++;
x/=2;
}
fprintf(stdout, "\n");
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}
I think that the code should return the right solution, but sometimes the output doesn't return the correct number.
Example of correct output:
./genBin 3
100
101
010
110
001
011
111
000
Example of wrong output (because of duplicates):
./genBin 3
110
110
110
001
011
111
111
000
I think that the problem is in the synchronization between the mutex and the printf.
Is there an alternative solution to avoid confusing results?
Your code contains a race condition. In main, you pass the address of your iteration variable, i, as the thread function's argument. Each new thread then races with the main thread to read the value of i (via the provided pointer) before the main thread increments it. One way you could address that problem would be to use a semaphore to make the main thread wait after creating each thread until that thread has dereferenced its argument.
Also, I don't think you need to use a mutex in genBin(). The only shared data it accesses is stdout, via fprintf(), and that function operates as if it locks an exclusive lock associated with the specified stream. Moreover, with the mutex you get essentially no actual concurrency because each thread holds the mutex locked for almost the complete duration of its execution.
The problem is in this part:
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &i)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
There's data race because you are passing the address of i to all threads. You could use an temp array to pass the individual number to each thread.
Thanks to everyone! You solved my problem. This is the corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
exit(EXIT_FAILURE);
}
int i;
int *temp;
num = atoi(argv[1]);
c = num;
r = 2;
for (i=1; i<num; i++) {
r=r*2;
}
temp = malloc(r*sizeof(int));
pthread_mutex_init(&mutex, NULL);
pthread_t* p;
p = malloc(r*sizeof(pthread_t));
for (i=0;i<r;i++) {
temp[i] = i;
}
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &temp[i])) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
for (i=0;i<r;i++) {
if (pthread_join(p[i], NULL)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
pthread_mutex_destroy(&mutex);
free(temp);
free(p);
pthread_exit(0);
}
void *genBin (void *arg) {
int x;
int i=0;
int *v;
v = malloc(num*sizeof(int));
x = *((int*)arg);
for (i=0; i<num; i++) {
v[i] = x%2;
x/=2;
}
pthread_mutex_lock(&mutex);
for (i=0; i<num; i++) {
fprintf(stdout, "%d", v[i]);
}
fprintf(stdout, "\n");
pthread_mutex_unlock(&mutex);
free(v);
pthread_exit(0);
}
I am having a problem in the synchronisation of threads. I m trying to implement sleeping barber problem in a different approach.
When i run the code the threads run in a completely vague manner.
When i add join to the threads the processes run one by one which is not required.
I know the solutions to the sleeping barber problem but can anybody tell me what is the problem with this code.?
Thank You
#include<stdio.h>
#include<pthread.h>
#include<time.h>
#include <unistd.h>
#include<semaphore.h>
#define n 1
#define n1 50
int status[n];
int b=0;
sem_t mutex;
sem_t barber;
void *barb()
{
printf("Barber Sleeping\n");
b=1;
sem_wait(&barber);
printf("Barber woke up\n");
sleep(1);
b=0;
}
void *handler(void *ptr)
{
int x;
x = *((int *) ptr);
int flag=0;
int i=0;
int cnt=0;
for(i=0;i<n;i++)
{
if(status[i]==1)
{
flag=1;
cnt++;
}
}
printf("Count=%d",cnt);
if(cnt==n)
{
printf("%d Customer Returned\n",x);
return 0;
}
if(flag==1)
{
status[x]=1;
printf("%d Customer waiting\n",x);
sem_wait(&mutex);
}
if(b==1)
{
printf("Customer %d woke up barber",x);
sem_post(&barber);
}
printf("Cutting Hair of customer %d\n",x);
status[x]=1;
sleep(5);
flag=0;
for(i=0;i<n;i++)
{
if(status[i]==1)
{
flag=1;
}
}
status[x]=0;
printf("Finished cutting Hair of customer %d\n",x);
if(flag==1)
sem_post(&mutex);
}
int main()
{
sem_init(&mutex, 0, n);
sem_init(&barber, 0, 1);
pthread_t thread[n1];
pthread_t barber;
int i=0;
for(i=0;i<n;i++)
{
status[i]=0;
}
pthread_create(&barber,NULL,barb,NULL);
pthread_join(barber,NULL);
for(i=0;i<n1;i++)
{
sleep(1);
printf("Customer entered %d\n",i);
pthread_create(&thread[i], NULL, handler, (void *)&i);
//pthread_join(thread[i],NULL);
}
for(i=0;i<n1;i++)
{
//pthread_join(thread[i],NULL);
}
//sem_post(&barber);
}
I have the code to help you
#define _REENTRANT
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
// The maximum number of customer threads.
#define MAX_CUSTOMERS 25
// Function prototypes...
void *customer(void *num);
void *barber(void *);
void randwait(int secs);
// Define the semaphores.
// waitingRoom Limits the # of customers allowed
// to enter the waiting room at one time.
sem_t waitingRoom;
// barberChair ensures mutually exclusive access to
// the barber chair.
sem_t barberChair;
// barberPillow is used to allow the barber to sleep
// until a customer arrives.
sem_t barberPillow;
// seatBelt is used to make the customer to wait until
// the barber is done cutting his/her hair.
sem_t seatBelt;
// Flag to stop the barber thread when all customers
// have been serviced.
int allDone = 0;
int main(int argc, char *argv[]) {
pthread_t btid;
pthread_t tid[MAX_CUSTOMERS];
long RandSeed;
int i, numCustomers, numChairs;
int Number[MAX_CUSTOMERS];
// Check to make sure there are the right number of
// command line arguments.
if (argc != 4) {
printf("Use: SleepBarber <Num Customers> <Num Chairs> <rand seed>\n");
exit(-1);
}
// Get the command line arguments and convert them
// into integers.
numCustomers = atoi(argv[1]);
numChairs = atoi(argv[2]);
RandSeed = atol(argv[3]);
// Make sure the number of threads is less than the number of
// customers we can support.
if (numCustomers > MAX_CUSTOMERS) {
printf("The maximum number of Customers is %d.\n", MAX_CUSTOMERS);
exit(-1);
}
printf("\nSleepBarber.c\n\n");
printf("A solution to the sleeping barber problem using semaphores.\n");
// Initialize the random number generator with a new seed.
srand48(RandSeed);
// Initialize the numbers array.
for (i=0; i<MAX_CUSTOMERS; i++) {
Number[i] = i;
}
// Initialize the semaphores with initial values...
sem_init(&waitingRoom, 0, numChairs);
sem_init(&barberChair, 0, 1);
sem_init(&barberPillow, 0, 0);
sem_init(&seatBelt, 0, 0);
// Create the barber.
pthread_create(&btid, NULL, barber, NULL);
// Create the customers.
for (i=0; i<numCustomers; i++) {
pthread_create(&tid[i], NULL, customer, (void *)&Number[i]);
}
// Join each of the threads to wait for them to finish.
for (i=0; i<numCustomers; i++) {
pthread_join(tid[i],NULL);
}
// When all of the customers are finished, kill the
// barber thread.
allDone = 1;
sem_post(&barberPillow); // Wake the barber so he will exit.
pthread_join(btid,NULL);
}
void *customer(void *number) {
int num = *(int *)number;
// Leave for the shop and take some random amount of
// time to arrive.
printf("Customer %d leaving for barber shop.\n", num);
randwait(5);
printf("Customer %d arrived at barber shop.\n", num);
// Wait for space to open up in the waiting room...
sem_wait(&waitingRoom);
printf("Customer %d entering waiting room.\n", num);
// Wait for the barber chair to become free.
sem_wait(&barberChair);
// The chair is free so give up your spot in the
// waiting room.
sem_post(&waitingRoom);
// Wake up the barber...
printf("Customer %d waking the barber.\n", num);
sem_post(&barberPillow);
// Wait for the barber to finish cutting your hair.
sem_wait(&seatBelt);
// Give up the chair.
sem_post(&barberChair);
printf("Customer %d leaving barber shop.\n", num);
}
void *barber(void *junk) {
// While there are still customers to be serviced...
// Our barber is omnicient and can tell if there are
// customers still on the way to his shop.
while (!allDone) {
// Sleep until someone arrives and wakes you..
printf("The barber is sleeping\n");
sem_wait(&barberPillow);
// Skip this stuff at the end...
if (!allDone) {
// Take a random amount of time to cut the
// customer's hair.
printf("The barber is cutting hair\n");
randwait(3);
printf("The barber has finished cutting hair.\n");
// Release the customer when done cutting...
sem_post(&seatBelt);
}
else {
printf("The barber is going home for the day.\n");
}
}
}
void randwait(int secs) {
int len;
// Generate a random number...
len = (int) ((drand48() * secs) + 1);
sleep(len);
}