Reputation: 2329
So I managed to get my program running but for some reason, no customer walks in the bar unless the customer before him/her leaves the bar first, how can I fix it? I tried a mutex_lock but I might've implemented it wrong, here is what I have from my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;
pthread_mutex_t serve = PTHREAD_MUTEX_INITIALIZER;
void Bartender(int);
void EnterBar(int);
void OrderStart(int);
void ServeStart(int);
void ServeDone(int);
void OrderDone(int);
void DrinkBeer(int);
void LeaveBar(int);
void* Customer(void*);
void Bartender(int cid)
{
ServeStart(cid);
ServeDone(cid);
}
void* Customer(void* id)
{
int cid =(int)id;
EnterBar(cid);
LeaveBar(cid);
return NULL;
}
void EnterBar(int cid){
sem_wait(&sem); //decrease semaphore
printf("Customer %d enters the bar.\n", cid);
int cups;
for(cups=0;cups<(cid%3+1);cups++){
pthread_mutex_lock(&serve);
OrderStart(cid);
OrderDone(cid);
DrinkBeer(cid);
pthread_mutex_unlock(&serve);
}
}
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);
sem_post( &sem ); //increase semaphore
}
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;
int num_customers = atoi(argv[1]); //number of customers
int capacity = atoi(argv[2]); //bar capacity
if(num_customers > 0 && capacity > 0){
rc = sem_init( &sem, 0, capacity );
if (rc)
{
printf("ERROR; return code from sem_init() is %ld\n",rc);
exit(-1);
}
//pthread_t threads[num_customers];
pthread_t *threads = (pthread_t*)malloc(num_customers*sizeof(pthread_t));
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);
//printf("CAPACITY: %d\n", capacity);
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);
sem_destroy(&sem); //destroy semaphore
}
else{
printf("ERROR: Both parameters should be a valid positive numbers.");
exit(-1);
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
It should allow multiple customers in the bar, and to leave after the finish drinking their beers, not after the customer before them leaves. Do I need a thread for the bartender? Any suggestions??
Upvotes: 0
Views: 484
Reputation: 24847
What's with all this mutex gunge? What's wrong with a couple semaphores, one 'barAccess', initialized to the bar capacity, one 'barStaff', init. to the number of bartenders?
#define slaughtered (beerCount==10)
{
beerCount=0;
wait(barAccess);
do{
wait(barStaff);
sleep(pouringTime);
signal(barstaff);
sleep(drinkingTime);
beerCount++;
}while(!slaughtered);
signal(barAccess);
};
If this bar has regular customers, you can add another while(true) loop round it with a 'sleep(soberUp);' after each session in the boozer.
It's also easy to vary the number of barstaff during opening time. Just add more 'barStaff' units or steal some away.
If it gets really busy, you might want to open the lounge bar as well to increase capacity - just all more barAccess units in a loop.
Closing time should be fun. You need to persuade the customers to leave and not allow any more in. Maybe the customers should leave if they don't get served in a reasonable time. You could then suck out all the barstaff so the customers can't get served and gather in all the barAccess units so new customers can't get in. Eventually, the bar will be empty for today. When you open up the next day, shove in the barstaff first, then the barAccess units and watch the rush to get served!
Upvotes: 1
Reputation: 27542
You don't have the problem you think you have. I made the following changes.
(1) //add globals
int count = 0;
pthread_mutex_t mutCount = PTHREAD_MUTEX_INITIALIZER;
(2) Add to counter of people in bar and print out
void EnterBar(int cid)
{
sem_wait(&sem); //decrease semaphore
printf("Customer %d enters the bar.\n", cid);
pthread_mutex_lock(&mutCount);
count++;
printf("There are %i customers in the bar\n", count);
pthread_mutex_unlock(&mutCount);
int cups;
for (cups = 0;cups < (cid % 3 + 1);cups++)
{
pthread_mutex_lock(&serve);
OrderStart(cid);
OrderDone(cid);
DrinkBeer(cid);
pthread_mutex_unlock(&serve);
}
}
(3) decrement count of customers in bar when they leav
void LeaveBar(int cid)
{
printf("Customer %d leaves the bar.\n", cid);
pthread_mutex_lock(&mutCount);
count--;
pthread_mutex_unlock(&mutCount);
sem_post( &sem ); //increase semaphore
}
(4) In main change usleep to something worthwhile
if (random() > RAND_MAX / 2)
usleep(100);
(5) I ran with: barthread 20 15 | grep "There are"
(6) I get the following output:
There are 1 customers in the bar
There are 2 customers in the bar
There are 1 customers in the bar
There are 3 customers in the bar
There are 4 customers in the bar
There are 5 customers in the bar
There are 6 customers in the bar
There are 7 customers in the bar
There are 6 customers in the bar
There are 6 customers in the bar
There are 5 customers in the bar
There are 5 customers in the bar
There are 5 customers in the bar
There are 6 customers in the bar
There are 4 customers in the bar
There are 4 customers in the bar
There are 5 customers in the bar
There are 6 customers in the bar
There are 7 customers in the bar
There are 8 customers in the bar
Upvotes: 1
Reputation: 1609
I think this is a correct behavior, right ? Customer 2 is the first in the bar but leaves after customer 1.
[amb@localhost ~]$ ./a.out 3 2
In main: creating thread 0
In main: creating thread 1
In main: creating thread 2
Customer 2 enters the bar.
Customer 2 asks for beer.
Bartender starts to serve customer 2.
Bartender is done serving customer 2.
Customer 2 gets the beer.
Customer 2 drinks the beer for 7 seconds.
Customer 1 enters the bar.
Customer 1 asks for beer.
Bartender starts to serve customer 1.
Bartender is done serving customer 1.
Customer 1 gets the beer.
Customer 1 drinks the beer for 8 seconds.
Customer 2 asks for beer.
Bartender starts to serve customer 2.
Bartender is done serving customer 2.
Customer 2 gets the beer.
Customer 2 drinks the beer for 6 seconds.
Customer 1 asks for beer.
Bartender starts to serve customer 1.
Bartender is done serving customer 1.
Customer 1 gets the beer.
Customer 1 drinks the beer for 4 seconds.
Customer 1 leaves the bar.
Customer 0 enters the bar.
Customer 0 asks for beer.
Bartender starts to serve customer 0.
Bartender is done serving customer 0.
Customer 0 gets the beer.
Customer 0 drinks the beer for 6 seconds.
Customer 2 asks for beer.
Bartender starts to serve customer 2.
Bartender is done serving customer 2.
Customer 2 gets the beer.
Customer 2 drinks the beer for 7 seconds.
Customer 0 leaves the bar.
Customer 2 leaves the bar.
Upvotes: 1
Reputation: 1609
#include <unistd.h>
and modify this functions
void DrinkBeer(int cid)
{
printf("Customer %d drinks the beer for 10 seconds.\n", cid);
sleep(10);
}
void LeaveBar(int cid)
{
printf("Customer %d leaves the bar (takes 10 sec).\n", cid);
sem_post( &sem ); //increase semaphore
sleep(10);
}
See how it behaves now. You need some sleep functions in there so the thread can sleep and to observe better how the other threads are working. Does it function as it should with this modifications ?
Upvotes: 2