Goal
To give you
some routine in mapping real-world problems to multithreaded programmed
solutions
1. Implement Park-a-Lot
2000 (60%)
1.1 First step
Implement
the PLCS and verify that it works with a single car that enters the parking
lot, waits there for some time and exits the parking lot again.
Question: Which statement is valid and why?
1. One
conditional variable used with multiple mutexes.
2.
Multiple conditional variables used in a single mutex.
The second
statement is true because we are dealing with multiple threads. By using
multiple conditional variables we can control which thread receive what signal.
1.1 First step - Solution
#include <pthread.h>
#include <iostream>
using namespace std;
int carWaitingIn=0;
int carWaitingOut=0;
int numberOfcars=0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t carCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t entryCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t exitCond = PTHREAD_COND_INITIALIZER;
void *entry(void *arg)
{
while(true)
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingIn)
{pthread_cond_wait(&entryCond,&mutex);}
pthread_cond_signal(&carCond);
--carWaitingIn;
{pthread_cond_wait(&entryCond,&mutex);}
pthread_cond_signal(&carCond);
--carWaitingIn;
++numberOfcars;
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *exit(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingOut)
{pthread_cond_wait(&exitCond,&mutex);}
{pthread_cond_wait(&exitCond,&mutex);}
--carWaitingOut;
--numberOfcars;
pthread_cond_signal(&carCond);
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *car(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
++carWaitingIn;
pthread_cond_signal(&entryCond);
while(carWaitingIn)
{pthread_cond_wait(&carCond,&mutex);}
cout
<< "Number
of cars in parking lot: " << numberOfcars << endl;
pthread_mutex_unlock(&mutex);
sleep(5);
pthread_mutex_lock(&mutex);
++carWaitingOut;
pthread_cond_signal(&exitCond);
while(carWaitingOut)
{pthread_cond_wait(&carCond,&mutex);}
cout
<< "Number
of cars in parking lot: " << numberOfcars << endl;
pthread_mutex_unlock(&mutex);
sleep(5);
}
return (void *)0;
}
int main(void)
{
void *exit_status;
int s;
cout<<"Creating threads"<<endl;
pthread_t carThread;
pthread_t entryThread;
pthread_t exitThread;
int value = 0;
s=pthread_create(&entryThread, NULL, entry,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
s=pthread_create(&carThread, NULL, car,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
s=pthread_create(&exitThread, NULL, exit ,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
pthread_join(carThread, &exit_status);
pthread_join(entryThread, &exit_status);
pthread_join(exitThread, &exit_status);
cout<<"Threads terminated"<<endl;
return 0;
}
1.2 The grandiose test
Repeat the
above test this time with multiple cars. Furthermore every car should wait a
different amount of time in the parking lot before exiting. In this scenario
the car park does not have an upper bound on the number of cars it has space
for.
Verify that
all cars are able to enter and exit as would be expected.
Consider
and argue when and why you are to use pthread_cond_broadcast(), also explain
what it does.
1.2 The grandiose test - Solution
1.2 The grandiose test - Solution
#include <pthread.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
int carWaitingIn=0;
int carWaitingOut=0;
int numberOfcars=0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t carCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t entryCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t exitCond = PTHREAD_COND_INITIALIZER;
void *entry(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingIn)
{pthread_cond_wait(&entryCond,&mutex);}
//cout <<
"test1" << endl;
pthread_cond_signal(&carCond);
//cout <<
"test2" << endl;
--carWaitingIn;
++numberOfcars;
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *exit(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingOut)
{pthread_cond_wait(&exitCond,&mutex);}
--carWaitingOut;
--numberOfcars;
pthread_cond_signal(&carCond);
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *car(void *arg)
{
int carNumber = (int)arg;
while(true)
{
pthread_mutex_lock(&mutex);
++carWaitingIn;
cout
<< "Car
no. " <<
carNumber << "
waiting at entry" << endl;
pthread_cond_signal(&entryCond);
while(carWaitingIn)
{pthread_cond_wait(&carCond,&mutex);}
cout
<< "Car
no. " <<
carNumber<< "
at parking lot"
<< endl;
pthread_mutex_unlock(&mutex);
sleep(rand() % 5 + 3);
pthread_mutex_lock(&mutex);
++carWaitingOut;
cout
<< "Car
no. " <<
carNumber << "
waiting at exit" << endl;
pthread_cond_signal(&exitCond);
while(carWaitingOut)
{pthread_cond_wait(&carCond,&mutex);}
pthread_mutex_unlock(&mutex);
sleep(5);
}
return (void *)0;
}
int main(void)
{
void *exit_status;
int s;
cout<<"Creating threads"<<endl;
pthread_t carThread[5];
pthread_t entryThread;
pthread_t exitThread;
int value = 0;
s=pthread_create(&entryThread, NULL, entry,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
for(int i=0;i<5;i++)
{
s=pthread_create(&carThread[i], NULL, car, (void *)i);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
}
s=pthread_create(&exitThread, NULL, exit ,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
for(int i=0;i<5;i++)
{
pthread_join(carThread[i],
&exit_status);
}
pthread_join(entryThread, &exit_status);
pthread_join(exitThread, &exit_status);
cout<<"Threads terminated"<<endl;
return 0;
}
Console Output:
2. Extending PCLS, now
with a limit on the number of cars (40%)
#include <pthread.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
int carWaitingIn=0;
int carWaitingOut=0;
int numberOfcars=0;
int maxCars=5;
bool port = false;
bool sensor = false;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t carCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t entryCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t exitCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t freeSpace = PTHREAD_COND_INITIALIZER;
static pthread_cond_t carEntered = PTHREAD_COND_INITIALIZER;
void *entry(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingIn)
{pthread_cond_wait(&entryCond,&mutex);}
port
= true;
pthread_cond_signal(&carCond);
while(sensor == false)
pthread_cond_wait(&carEntered, &mutex);
port=false;
sensor
= false;
--carWaitingIn;
++numberOfcars;
while(numberOfcars >= maxCars)
{pthread_cond_wait(&freeSpace,&mutex);
}
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *exit(void *arg)
{
while(true)
{
pthread_mutex_lock(&mutex);
while(!carWaitingOut)
{pthread_cond_wait(&exitCond,&mutex);}
--carWaitingOut;
--numberOfcars;
pthread_cond_signal(&carCond);
if(numberOfcars<maxCars)
{
pthread_cond_signal(&freeSpace);
}
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
void *car(void *arg)
{
int carNumber = (int)arg;
while(true)
{
pthread_mutex_lock(&mutex);
++carWaitingIn;
cout
<< "Car
no. " <<
carNumber << "
waiting at entry" << endl;
pthread_cond_signal(&entryCond);
while(!port)
pthread_cond_wait(&carCond,&mutex);
sensor = true;
pthread_cond_signal(&carEntered);
cout
<< "Car
no. " <<
carNumber<< "
at parking lot"
<< endl;
pthread_mutex_unlock(&mutex);
sleep(rand() % 5 + 3);
pthread_mutex_lock(&mutex);
++carWaitingOut;
cout
<< "Car
no. " <<
carNumber << "
waiting at exit" << endl;
pthread_cond_signal(&exitCond);
while(carWaitingOut)
{pthread_cond_wait(&carCond,&mutex);}
pthread_mutex_unlock(&mutex);
sleep(5);
}
return (void *)0;
}
int main(void)
{
void *exit_status;
int s;
cout<<"Creating threads"<<endl;
pthread_t carThread[10];
pthread_t entryThread;
pthread_t exitThread;
int value = 0;
s=pthread_create(&entryThread, NULL, entry,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
for(int i=0;i<10;i++)
{
s=pthread_create(&carThread[i], NULL, car, (void *)i);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
}
s=pthread_create(&exitThread, NULL, exit ,
&value);
if(s != 0)
{cout<<"Thread create
error"<<endl;}
for(int i=0;i<10;i++)
{
pthread_join(carThread[i],
&exit_status);
}
pthread_join(entryThread, &exit_status);
pthread_join(exitThread, &exit_status);
cout<<"Threads terminated"<<endl;
return 0;
}
Console Output:


The goal of the exercise is to give you some routine in mapping real-world problems to multithreaded programmed solutions. You have completed the goal by making the program work. There are some minor details you could consider:
ReplyDeleteYou should have included a flowchart or pseudo code in your solution as described in the exercise, because it would make it easier to understand in what order everything happens. It would be a good idea to write when a car has left the parking lot, to check that it is able to pass through the exit guard. To make your code easier to understand you could use smaller spacing, but this is probably a limit in blogspot.