Improved comments, prepped for submission
This commit is contained in:
parent
175de8b626
commit
164ba99e95
@ -1,6 +1,12 @@
|
|||||||
/* Dempsey-Jensen, Brychan, 14299890, Assignment 2, 159.341 */
|
/* Dempsey-Jensen, Brychan, 14299890, Assignment 2, 159.341 */
|
||||||
/* Use semaphores to prevent race conditions in a concurrent lift-simulator */
|
/* Use semaphores to prevent race conditions in a concurrent lift-simulator */
|
||||||
|
|
||||||
|
// *************
|
||||||
|
// Note:
|
||||||
|
// Uncommenting this definition will print populations & the number of people next to the building
|
||||||
|
|
||||||
|
// #define POPULATIONS
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// --- 159.341 Assignment 2 - Lift Simulator ---
|
// --- 159.341 Assignment 2 - Lift Simulator ---
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
@ -25,7 +31,7 @@
|
|||||||
//#define SUPERSLOW
|
//#define SUPERSLOW
|
||||||
//#define SLOW
|
//#define SLOW
|
||||||
//#define FAST
|
//#define FAST
|
||||||
#define SUPERFAST
|
#define SUPERFAST // Original FAST
|
||||||
|
|
||||||
#if defined(SUPERSLOW)
|
#if defined(SUPERSLOW)
|
||||||
#define LIFTSPEED 500 // The time it takes for the lift to move one floor
|
#define LIFTSPEED 500 // The time it takes for the lift to move one floor
|
||||||
@ -59,8 +65,7 @@
|
|||||||
#if defined(_WIN32) || defined(WIN32)
|
#if defined(_WIN32) || defined(WIN32)
|
||||||
#define true TRUE
|
#define true TRUE
|
||||||
#endif
|
#endif
|
||||||
// Print the number of people in the lifts & on the floors
|
|
||||||
//#define POPULATIONS
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// Information about a floor in the building
|
// Information about a floor in the building
|
||||||
@ -71,8 +76,9 @@ typedef struct
|
|||||||
int waitingtogodown; // The number of people waiting to go down
|
int waitingtogodown; // The number of people waiting to go down
|
||||||
semaphore up_arrow; // People going up wait on this
|
semaphore up_arrow; // People going up wait on this
|
||||||
semaphore down_arrow; // People going down wait on this
|
semaphore down_arrow; // People going down wait on this
|
||||||
semaphore queueInteraction; // People can't all press a button at the same time
|
// People can't all press a button at the same time
|
||||||
} floor_info;
|
semaphore queueInteraction;
|
||||||
|
} floor_info;
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// Information about a lift
|
// Information about a lift
|
||||||
@ -85,6 +91,7 @@ typedef struct
|
|||||||
int peopleinlift; // The number of people in the lift
|
int peopleinlift; // The number of people in the lift
|
||||||
int stops[NFLOORS]; // How many people are going to each floor
|
int stops[NFLOORS]; // How many people are going to each floor
|
||||||
semaphore stopsem[NFLOORS]; // People in the lift wait on one of these
|
semaphore stopsem[NFLOORS]; // People in the lift wait on one of these
|
||||||
|
// control whether the lift is currently adding someone
|
||||||
semaphore addToStop;
|
semaphore addToStop;
|
||||||
} lift_info;
|
} lift_info;
|
||||||
|
|
||||||
@ -92,11 +99,14 @@ typedef struct
|
|||||||
// Some global variables
|
// Some global variables
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
floor_info floors[NFLOORS];
|
floor_info floors[NFLOORS];
|
||||||
lift_info *targetLift[NFLOORS]; // 2-dimensional array of the lift
|
|
||||||
|
// keep track of the current target lift on the floor (and a semaphore to prevent this changing prematurely)
|
||||||
|
lift_info *targetLift[NFLOORS];
|
||||||
semaphore targetLiftSelect[NFLOORS];
|
semaphore targetLiftSelect[NFLOORS];
|
||||||
|
|
||||||
// Bound all printing to this semaphore
|
// Bind all printing to this semaphore, so that the target position can't be changed before printing.
|
||||||
semaphore printSemaphore;
|
semaphore printSemaphore;
|
||||||
|
|
||||||
// If printing people counts, int array and semaphore to keep track of them
|
// If printing people counts, int array and semaphore to keep track of them
|
||||||
#ifdef POPULATIONS
|
#ifdef POPULATIONS
|
||||||
semaphore updateFloorCount;
|
semaphore updateFloorCount;
|
||||||
@ -105,25 +115,14 @@ int floorCount[NFLOORS];
|
|||||||
int floorCountZeroInc[NFLOORS];
|
int floorCountZeroInc[NFLOORS];
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// Print a string on the screen at position (x,y)
|
// Prints a string, with a delay - but it is zero ms
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
void print_at_xy_fast(int x, int y, const char *s)
|
void print_at_xy_fast(int x, int y, const char *s)
|
||||||
{
|
{
|
||||||
// Lock our print to just one thread (stops x,y from changing)
|
|
||||||
semaphore_wait(&printSemaphore);
|
semaphore_wait(&printSemaphore);
|
||||||
// Move cursor to (x,y)
|
|
||||||
gotoxy(x, y);
|
gotoxy(x, y);
|
||||||
|
|
||||||
// Slow things down
|
|
||||||
Sleep(0);
|
Sleep(0);
|
||||||
|
|
||||||
// Print the string
|
|
||||||
printf("%s", s);
|
printf("%s", s);
|
||||||
|
|
||||||
// Move cursor out of the way
|
|
||||||
gotoxy(42, NFLOORS + 2);
|
|
||||||
// flush the stream and release the semaphore
|
|
||||||
//fflush(stdout);
|
|
||||||
semaphore_signal(&printSemaphore);
|
semaphore_signal(&printSemaphore);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -179,9 +178,8 @@ void get_into_lift(lift_info *lift, int direction)
|
|||||||
waiting = &floors[lift->position].waitingtogodown;
|
waiting = &floors[lift->position].waitingtogodown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Problems here are primarily state consistency. Between the start of the conditional, the number of waiting people can change, resulting
|
// Waiting can begin to be decremented while another thread enters the loop. Therefore we
|
||||||
// in the number of waiting people dropping below zero.
|
// need to prevent an attempt to remove someone who has already been removed
|
||||||
// For all the people waiting
|
|
||||||
while (*waiting)
|
while (*waiting)
|
||||||
{
|
{
|
||||||
// Check if lift is empty
|
// Check if lift is empty
|
||||||
@ -191,8 +189,7 @@ void get_into_lift(lift_info *lift, int direction)
|
|||||||
lift->direction = direction;
|
lift->direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check there are people waiting and lift isn't full. Ignore in-progress (moving into lift) people
|
// Prevent other threads from evaluating the conditional until waiting is decremented
|
||||||
// must check here
|
|
||||||
semaphore_wait(&floors[lift->position].queueInteraction);
|
semaphore_wait(&floors[lift->position].queueInteraction);
|
||||||
if (lift->peopleinlift < MAXNOINLIFT && *waiting)
|
if (lift->peopleinlift < MAXNOINLIFT && *waiting)
|
||||||
{
|
{
|
||||||
@ -205,16 +202,20 @@ void get_into_lift(lift_info *lift, int direction)
|
|||||||
|
|
||||||
// Wait for person to get into lift
|
// Wait for person to get into lift
|
||||||
Sleep(GETINSPEED);
|
Sleep(GETINSPEED);
|
||||||
// Need a sem here
|
|
||||||
// Wait til we can be the lift that is loading
|
|
||||||
|
// Wait to set the current lift for the floor as our current lift. We maintain this lock,
|
||||||
|
// while the person whom is later signalled will relase it
|
||||||
semaphore_wait(&targetLiftSelect[lift->position]);
|
semaphore_wait(&targetLiftSelect[lift->position]);
|
||||||
targetLift[lift->position] = lift;
|
targetLift[lift->position] = lift;
|
||||||
// lock the addtostop
|
// lock the addtostop, to prevent the lift leaving without the passenger
|
||||||
semaphore_wait(&lift->addToStop);
|
semaphore_wait(&lift->addToStop);
|
||||||
|
// Finally, "open the doors and let someone in"
|
||||||
semaphore_signal(s);
|
semaphore_signal(s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// There is no-one else waiting; so release our lock
|
||||||
semaphore_signal(&floors[lift->position].queueInteraction);
|
semaphore_signal(&floors[lift->position].queueInteraction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -236,9 +237,8 @@ void *lift_thread(void *p)
|
|||||||
lift.position = 0; // Lift starts on ground floor
|
lift.position = 0; // Lift starts on ground floor
|
||||||
lift.direction = UP; // Lift starts going up
|
lift.direction = UP; // Lift starts going up
|
||||||
lift.peopleinlift = 0; // Lift starts empty
|
lift.peopleinlift = 0; // Lift starts empty
|
||||||
// lift is ok with loading a single person
|
// A lift can load a single person at a time
|
||||||
semaphore_create(&lift.addToStop, 1);
|
semaphore_create(&lift.addToStop, 1);
|
||||||
//semaphore_create(&lift.buttonPress, 1);
|
|
||||||
|
|
||||||
for (i = 0; i < NFLOORS; i++)
|
for (i = 0; i < NFLOORS; i++)
|
||||||
{
|
{
|
||||||
@ -271,9 +271,10 @@ void *lift_thread(void *p)
|
|||||||
// Drop off passengers on this floor
|
// Drop off passengers on this floor
|
||||||
while (lift.stops[lift.position] != 0)
|
while (lift.stops[lift.position] != 0)
|
||||||
{
|
{
|
||||||
// These are sequential, so don't need protecting
|
// These are sequential operations on just one thread (this lift), so don't need protecting here -
|
||||||
|
// The passenger is told to get out and then does work on the floor
|
||||||
|
|
||||||
// One less passenger in lift
|
// One less passenger in lift
|
||||||
|
|
||||||
lift.peopleinlift--;
|
lift.peopleinlift--;
|
||||||
|
|
||||||
// One less waiting to get off at this floor
|
// One less waiting to get off at this floor
|
||||||
@ -309,9 +310,8 @@ void *lift_thread(void *p)
|
|||||||
// Erase lift from screen
|
// Erase lift from screen
|
||||||
print_at_xy(no * 4 + 1, NFLOORS - lift.position, (lift.direction + 1 ? " " : lc));
|
print_at_xy(no * 4 + 1, NFLOORS - lift.position, (lift.direction + 1 ? " " : lc));
|
||||||
|
|
||||||
// Move lift
|
// Move lift, but make sure it doesn't move before someone is fully loaded
|
||||||
// Hold the lift while someone is being added, before moving off
|
// this really could go anywhere, but it fits the metaphor to wrap it here (doesn't have to wrap anything)
|
||||||
// this really could go anywhere, but it fits the metaphor to wrap it here (doesn't need to wrap anything)
|
|
||||||
semaphore_wait(&lift.addToStop);
|
semaphore_wait(&lift.addToStop);
|
||||||
lift.position += lift.direction;
|
lift.position += lift.direction;
|
||||||
semaphore_signal(&lift.addToStop);
|
semaphore_signal(&lift.addToStop);
|
||||||
@ -353,11 +353,12 @@ void *person_thread(void *p)
|
|||||||
if (to > from)
|
if (to > from)
|
||||||
{
|
{
|
||||||
// One more person waiting to go up
|
// One more person waiting to go up
|
||||||
|
// Only one can press the button at a time. Ensure the person is printed to the console before releasing the
|
||||||
|
// semaphore so that there are no ghosts left in the console
|
||||||
semaphore_wait(&floors[from].queueInteraction);
|
semaphore_wait(&floors[from].queueInteraction);
|
||||||
floors[from].waitingtogoup++;
|
floors[from].waitingtogoup++;
|
||||||
print_at_xy(NLIFTS * 4 + floors[from].waitingtogoup + floors[from].waitingtogodown, NFLOORS - from, pr);
|
print_at_xy(NLIFTS * 4 + floors[from].waitingtogoup + floors[from].waitingtogodown, NFLOORS - from, pr);
|
||||||
semaphore_signal(&floors[from].queueInteraction);
|
semaphore_signal(&floors[from].queueInteraction);
|
||||||
// Print person waiting
|
|
||||||
|
|
||||||
s = &floors[from].up_arrow;
|
s = &floors[from].up_arrow;
|
||||||
// Wait for a lift to arrive (going up)
|
// Wait for a lift to arrive (going up)
|
||||||
@ -369,12 +370,11 @@ void *person_thread(void *p)
|
|||||||
floors[from].waitingtogodown++;
|
floors[from].waitingtogodown++;
|
||||||
print_at_xy(NLIFTS * 4 + floors[from].waitingtogoup + floors[from].waitingtogodown, NFLOORS - from, pr);
|
print_at_xy(NLIFTS * 4 + floors[from].waitingtogoup + floors[from].waitingtogodown, NFLOORS - from, pr);
|
||||||
semaphore_signal(&floors[from].queueInteraction);
|
semaphore_signal(&floors[from].queueInteraction);
|
||||||
// Print person waiting
|
|
||||||
// We want this to happen after the semaphore is released, so the person is added after any deletions
|
|
||||||
|
|
||||||
s = &floors[from].down_arrow;
|
s = &floors[from].down_arrow;
|
||||||
// Wait for a lift to arrive (going down)
|
// Wait for a lift to arrive (going down)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've pressed our button
|
// We've pressed our button
|
||||||
// waiting for a lift's doors to open
|
// waiting for a lift's doors to open
|
||||||
semaphore_wait(s);
|
semaphore_wait(s);
|
||||||
@ -382,6 +382,7 @@ void *person_thread(void *p)
|
|||||||
lift = targetLift[from];
|
lift = targetLift[from];
|
||||||
// Realease the targetLift ASAP so another lift can load someone
|
// Realease the targetLift ASAP so another lift can load someone
|
||||||
semaphore_signal(&targetLiftSelect[lift->position]);
|
semaphore_signal(&targetLiftSelect[lift->position]);
|
||||||
|
|
||||||
// GetIntoLift() continues its loop, from here (this passenger is signalled to enter; so we definitely need to hold a lock around
|
// GetIntoLift() continues its loop, from here (this passenger is signalled to enter; so we definitely need to hold a lock around
|
||||||
// this value)
|
// this value)
|
||||||
// When GetIntoLift() decides that a passenger should enter, it obtains a lock of addToStop.
|
// When GetIntoLift() decides that a passenger should enter, it obtains a lock of addToStop.
|
||||||
@ -390,21 +391,20 @@ void *person_thread(void *p)
|
|||||||
|
|
||||||
// We could do this by extending the targetLiftSelect semaphore through the same condition, but that would affect the performance of all lifts on this floor
|
// We could do this by extending the targetLiftSelect semaphore through the same condition, but that would affect the performance of all lifts on this floor
|
||||||
lift->stops[to]++;
|
lift->stops[to]++;
|
||||||
semaphore_signal(&lift->addToStop);
|
|
||||||
// Press button if we are the first
|
|
||||||
// Technically, the semaphore should extend through this conditional, but as it is only a read operation whose state is should to
|
|
||||||
// be greater than 0 here, it doesn't significantly matter to overwrite the char again (the performance impact is low)
|
|
||||||
if (lift->stops[to] == 1)
|
if (lift->stops[to] == 1)
|
||||||
{
|
{
|
||||||
// Print light for destination
|
// Print light for destination
|
||||||
print_at_xy(lift->no * 4 + 1 + 2, NFLOORS - to, "-");
|
print_at_xy(lift->no * 4 + 1 + 2, NFLOORS - to, "-");
|
||||||
}
|
}
|
||||||
|
// Person are fully added
|
||||||
|
semaphore_signal(&lift->addToStop);
|
||||||
|
|
||||||
semaphore_wait(&lift->stopsem[to]);
|
semaphore_wait(&lift->stopsem[to]);
|
||||||
// Wait until we are at the right floor
|
// Wait until we are at the right floor
|
||||||
|
|
||||||
|
|
||||||
#ifdef POPULATIONS
|
#ifdef POPULATIONS
|
||||||
|
// Prints the current location of all people in a line below the building
|
||||||
semaphore_wait(&updateFloorCount);
|
semaphore_wait(&updateFloorCount);
|
||||||
floorCount[to]++;
|
floorCount[to]++;
|
||||||
floorCount[from]--;
|
floorCount[from]--;
|
||||||
@ -415,7 +415,7 @@ void *person_thread(void *p)
|
|||||||
print_at_xy_fast((long long)p * 4 + 1, NFLOORS + 8, " ");
|
print_at_xy_fast((long long)p * 4 + 1, NFLOORS + 8, " ");
|
||||||
print_at_xy_fast((long long)p * 4 + 1, NFLOORS + 8, str);
|
print_at_xy_fast((long long)p * 4 + 1, NFLOORS + 8, str);
|
||||||
#endif
|
#endif
|
||||||
// Exit the lift
|
// Finally, exit the lift
|
||||||
from = to;
|
from = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,6 +489,7 @@ void *update_floor_counts(void *p)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int k;
|
int k;
|
||||||
|
// Iterations since the count on the floor was zero
|
||||||
char str2[18] = {';',' ','\t', 'i', 't', 'e', 'r', 's', ' ', 's', 'i', 'n', 'c', 'e', ' ', '0', ':', ' '};
|
char str2[18] = {';',' ','\t', 'i', 't', 'e', 'r', 's', ' ', 's', 'i', 'n', 'c', 'e', ' ', '0', ':', ' '};
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -546,11 +547,11 @@ int main()
|
|||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
c = getchar();
|
c = getchar();
|
||||||
//putchar (c);
|
} while (!(c == 10 || c == 12)); // Char is not \r or \n
|
||||||
} while (!(c == 10 || c == 12));
|
|
||||||
|
|
||||||
// Local variables
|
// Local variables
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
// init the print semaphore
|
||||||
semaphore_create(&printSemaphore, 0);
|
semaphore_create(&printSemaphore, 0);
|
||||||
// Initialise Building
|
// Initialise Building
|
||||||
for (i = 0; i < NFLOORS; i++)
|
for (i = 0; i < NFLOORS; i++)
|
||||||
@ -559,12 +560,13 @@ int main()
|
|||||||
floors[i].waitingtogodown = 0;
|
floors[i].waitingtogodown = 0;
|
||||||
semaphore_create(&floors[i].up_arrow, 0);
|
semaphore_create(&floors[i].up_arrow, 0);
|
||||||
semaphore_create(&floors[i].down_arrow, 0);
|
semaphore_create(&floors[i].down_arrow, 0);
|
||||||
semaphore_create(&floors[i].queueInteraction, 1); // This initially has one available button press
|
|
||||||
semaphore_create(&targetLiftSelect[i], 1); // This initially has one available button press
|
semaphore_create(&floors[i].queueInteraction, 1);
|
||||||
|
semaphore_create(&targetLiftSelect[i], 1);
|
||||||
#ifdef POPULATIONS
|
#ifdef POPULATIONS
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
semaphore_create(&updateFloorCount, 1); // Moved, to save excessive preprocessor tags
|
semaphore_create(&updateFloorCount, 1);
|
||||||
floorCount[0] = NPEOPLE;
|
floorCount[0] = NPEOPLE;
|
||||||
floorCountZeroInc[0] = 0;
|
floorCountZeroInc[0] = 0;
|
||||||
}
|
}
|
||||||
@ -574,8 +576,8 @@ int main()
|
|||||||
floorCountZeroInc[i] = 0;
|
floorCountZeroInc[i] = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
// --- Initialise any other semaphores ---
|
|
||||||
|
|
||||||
// Print Building
|
// Print Building
|
||||||
printbuilding();
|
printbuilding();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user