Mostly sorted

This commit is contained in:
Brychan Dempsey 2021-04-27 20:34:24 +12:00
parent ed6cc593b6
commit 33752ca3a1
2 changed files with 126 additions and 43 deletions

View File

@ -11,24 +11,35 @@
// -------------------------------------------------- // --------------------------------------------------
// Define Problem Size // Define Problem Size
// -------------------------------------------------- // --------------------------------------------------
#define NLIFTS 4 // The number of lifts in the building #define NLIFTS 20 // The number of lifts in the building
#define NFLOORS 20 // The number of floors in the building #define NFLOORS 20 // The number of floors in the building
#define NPEOPLE 20 // The number of people in the building #define NPEOPLE 200 // The number of people in the building
#define MAXNOINLIFT 10 // Maximum number of people in a lift #define MAXNOINLIFT 10 // Maximum number of people in a lift
// -------------------------------------------------- // --------------------------------------------------
// Define delay times (in milliseconds) // Define delay times (in milliseconds)
// -------------------------------------------------- // --------------------------------------------------
#define SLOW //#define SUPERSLOW
//#define SLOW
//#define FAST //#define FAST
#define SUPERFAST
#if defined(SLOW) #if defined(SUPERSLOW)
#define LIFTSPEED 50 // 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
#define GETINSPEED 50 // The time it takes to get into the lift #define GETINSPEED 250 // The time it takes to get into the lift
#define GETOUTSPEED 50 // The time it takes to get out of the lift #define GETOUTSPEED 250 // The time it takes to get out of the lift
#define PEOPLESPEED 10000 // The maximum time a person spends on a floor
#elif defined(SLOW)
#define LIFTSPEED 250 // The time it takes for the lift to move one floor
#define GETINSPEED 100 // The time it takes to get into the lift
#define GETOUTSPEED 100 // The time it takes to get out of the lift
#define PEOPLESPEED 100 // The maximum time a person spends on a floor #define PEOPLESPEED 100 // The maximum time a person spends on a floor
#elif defined(FAST) #elif defined(FAST)
#define LIFTSPEED 25 // The time it takes for the lift to move one floor
#define GETINSPEED 10 // The time it takes to get into the lift
#define GETOUTSPEED 10 // The time it takes to get out of the lift
#define PEOPLESPEED 10 // The maximum time a person spends on a floor
#elif defined(SUPERFAST)
#define LIFTSPEED 0 // The time it takes for the lift to move one floor #define LIFTSPEED 0 // The time it takes for the lift to move one floor
#define GETINSPEED 0 // The time it takes to get into the lift #define GETINSPEED 0 // The time it takes to get into the lift
#define GETOUTSPEED 0 // The time it takes to get out of the lift #define GETOUTSPEED 0 // The time it takes to get out of the lift
@ -50,6 +61,10 @@ typedef struct {
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 semaphore queueInteraction; // People can't all press a button at the same time
// Add a tracker to include how many people are currently moving into/out of a lift.
// These people are still considered to be waiting, but a thread is in the process of loading them
int inprogress_up;
int inprogress_down;
} floor_info; } floor_info;
// -------------------------------------------------- // --------------------------------------------------
@ -62,7 +77,10 @@ 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
semaphore load; // Semaphore stating if a thread is currently loading/unloading someone from the lift
semaphore loading;
// If the target floor is being selected (only one can press at a time)
semaphore buttonPress;
} lift_info; } lift_info;
// -------------------------------------------------- // --------------------------------------------------
@ -78,11 +96,11 @@ semaphore printSemaphore;
// Print a string on the screen at position (x,y) // Print a string on the screen at position (x,y)
// -------------------------------------------------- // --------------------------------------------------
void print_at_xy(int x, int y, const char *s) { void print_at_xy(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) // Move cursor to (x,y)
gotoxy(x,y); gotoxy(x,y);
// Slow things down // Slow things down
Sleep(1); Sleep(1);
@ -91,6 +109,7 @@ void print_at_xy(int x, int y, const char *s) {
// Move cursor out of the way // Move cursor out of the way
gotoxy(42, NFLOORS+2); gotoxy(42, NFLOORS+2);
// flush the stream and release the semaphore
fflush(stdout); fflush(stdout);
semaphore_signal(&printSemaphore); semaphore_signal(&printSemaphore);
} }
@ -101,7 +120,8 @@ void print_at_xy(int x, int y, const char *s) {
// -------------------------------------------------- // --------------------------------------------------
void get_into_lift(lift_info *lift, int direction) { void get_into_lift(lift_info *lift, int direction) {
// Local variables // Local variables
int *waiting; volatile int *waiting;
volatile int *inprogress;
semaphore *s; semaphore *s;
// Check lift direction // Check lift direction
@ -111,14 +131,18 @@ void get_into_lift(lift_info *lift, int direction) {
// Number of people waiting to go up // Number of people waiting to go up
waiting = &floors[lift->position].waitingtogoup; waiting = &floors[lift->position].waitingtogoup;
inprogress = &floors[lift->position].inprogress_up;
} else { } else {
// Use down_arrow semaphore // Use down_arrow semaphore
s = &floors[lift->position].down_arrow; s = &floors[lift->position].down_arrow;
// Number of people waiting to go down // Number of people waiting to go down
waiting = &floors[lift->position].waitingtogodown; waiting = &floors[lift->position].waitingtogodown;
inprogress = &floors[lift->position].inprogress_down;
} }
// Problems here are primarily state consistency. Between the start of the conditional, the number of waiting people can change, resulting
// in the number of waiting people dropping below zero.
// For all the people waiting // For all the people waiting
while(*waiting) { while(*waiting) {
// Check if lift is empty // Check if lift is empty
@ -127,24 +151,36 @@ 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 // Check there are people waiting and lift isn't full. Ignore in-progress (moving into lift) people
if(lift->peopleinlift < MAXNOINLIFT && *waiting) { // must check here
semaphore_wait(&floors[lift->position].queueInteraction);
if(lift->peopleinlift < MAXNOINLIFT && *waiting - *inprogress) {
//volatile int pos = floors[lift->position].waitingtogodown + floors[lift->position].waitingtogoup - (*inprogress);
(*inprogress)++;
volatile int vPos = lift->position;
//semaphore_signal(&floors[lift->position].queueInteraction);
// Add person to the lift // Add person to the lift
semaphore_wait(&lift->load);
lift->peopleinlift++; lift->peopleinlift++;
semaphore_signal(&lift->load); print_at_xy(NLIFTS*4+floors[lift->position].waitingtogodown + floors[lift->position].waitingtogoup, NFLOORS-vPos, " ");
// Capture the person's printed position while we have the
// Erase the person from the waiting queue //semaphore_signal(&floors[lift->position].queueInteraction);
print_at_xy(NLIFTS*4+floors[lift->position].waitingtogodown + floors[lift->position].waitingtogoup, NFLOORS-lift->position, " "); // Do the print, no need to hold the semaphore while this is going on
// One less person waiting // One less person waiting
// Note that while loading, the queue cannot change
//semaphore_wait(&floors[lift->position].queueInteraction);
(*waiting)--; (*waiting)--;
(*inprogress)--;
semaphore_signal(&floors[lift->position].queueInteraction);
// Wait for person to get into lift // Wait for person to get into lift
Sleep(GETINSPEED); Sleep(GETINSPEED);
targetLift[lift->position] = lift; targetLift[lift->position] = lift;
semaphore_signal(s); semaphore_signal(s);
} else { } else {
semaphore_signal(&floors[lift->position].queueInteraction);
break; break;
} }
} }
@ -164,8 +200,9 @@ 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
semaphore_create(&lift.load, 1); semaphore_create(&lift.loading, 1);
semaphore_create(&lift.buttonPress, 1);
for(i = 0; i < NFLOORS; i++) { for(i = 0; i < NFLOORS; i++) {
lift.stops[i]=0; // No passengers waiting lift.stops[i]=0; // No passengers waiting
@ -182,19 +219,21 @@ void* lift_thread(void *p) {
while(TRUE) { while(TRUE) {
// Print current position of the lift // Print current position of the lift
print_at_xy(no*4+1, NFLOORS-lift.position, lf); print_at_xy(no*4+1, NFLOORS-lift.position, lf);
// Wait for a while // Wait for a while
Sleep(LIFTSPEED); Sleep(LIFTSPEED);
// Drop off passengers on this floor // Drop off passengers on this floor
while (lift.stops[lift.position] != 0) { while (lift.stops[lift.position] != 0) {
// One less passenger in lift // One less passenger in lift
semaphore_wait(&lift.load); semaphore_wait(&lift.loading);
lift.peopleinlift--; lift.peopleinlift--;
semaphore_signal(&lift.loading);
// One less waiting to get off at this floor // One less waiting to get off at this floor
// Don't need a semaphore as nothing should read this value now
semaphore_wait(&lift.buttonPress);
lift.stops[lift.position]--; lift.stops[lift.position]--;
semaphore_signal(&lift.load); semaphore_signal(&lift.buttonPress);
// Wait for exit lift delay // Wait for exit lift delay
Sleep(GETOUTSPEED); Sleep(GETOUTSPEED);
@ -205,6 +244,7 @@ void* lift_thread(void *p) {
if(!lift.stops[lift.position]) { if(!lift.stops[lift.position]) {
// Clear the "-" // Clear the "-"
print_at_xy(no*4+1+2, NFLOORS-lift.position, " "); print_at_xy(no*4+1+2, NFLOORS-lift.position, " ");
} }
} }
// Check if lift is going up or is empty // Check if lift is going up or is empty
@ -260,6 +300,7 @@ 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
floors[from].waitingtogoup++; floors[from].waitingtogoup++;
//volatile int pos = floors[from].waitingtogoup +floors[from].waitingtogodown - floors[from].inprogress_down - floors[from].inprogress_up;
semaphore_signal(&floors[from].queueInteraction); semaphore_signal(&floors[from].queueInteraction);
// Print person waiting // Print person waiting
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);
@ -268,9 +309,11 @@ void* person_thread(void *p) {
} else { } else {
// One more person waiting to go down // One more person waiting to go down
floors[from].waitingtogodown++; floors[from].waitingtogodown++;
//volatile int pos = floors[from].waitingtogoup +floors[from].waitingtogodown - floors[from].inprogress_down - floors[from].inprogress_up;
semaphore_signal(&floors[from].queueInteraction); semaphore_signal(&floors[from].queueInteraction);
// Print person waiting // Print person waiting
print_at_xy(NLIFTS*4+floors[from].waitingtogodown+floors[from].waitingtogoup,NFLOORS-from, pr); // We want this to happen after the semaphore is released, so the person is added after any deletions
print_at_xy(NLIFTS*4+floors[from].waitingtogoup +floors[from].waitingtogodown,NFLOORS-from, pr);
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)
} }
@ -283,9 +326,9 @@ void* person_thread(void *p) {
// Add one to passengers waiting for floor // Add one to passengers waiting for floor
// Only one person enters at a time // Only one person enters at a time
semaphore_wait(&lift->load); semaphore_wait(&lift->buttonPress);
lift->stops[to]++; lift->stops[to]++;
semaphore_signal(&lift->load); semaphore_signal(&lift->buttonPress);
// Press button if we are the first // Press button if we are the first
if(lift->stops[to]==1) { if(lift->stops[to]==1) {
// Print light for destination // Print light for destination
@ -313,7 +356,6 @@ void printbuilding(void) {
// Clear Screen // Clear Screen
system(clear_screen); system(clear_screen);
// Print the whole building before anything else // Print the whole building before anything else
semaphore_wait(&printSemaphore);
// Print Roof // Print Roof
printf("%s", tl); printf("%s", tl);
for(l = 0; l < NLIFTS-1; l++) { for(l = 0; l < NLIFTS-1; l++) {
@ -342,19 +384,40 @@ void printbuilding(void) {
printf("Lift Simulation - Press CTRL-Break to exit\n"); printf("Lift Simulation - Press CTRL-Break to exit\n");
// Ensure buffer is written // Ensure buffer is written
fflush(stdout); fflush(stdout);
// Once the building has been printed, then we can those waiting to print that they may do so
semaphore_signal(&printSemaphore); semaphore_signal(&printSemaphore);
} }
// --------------------------------------------------
// Iterate through the floors and update the queue size
// --------------------------------------------------
void* update_floor_counts(void *p){
while(TRUE){
int i;
for (i = 0; i < NFLOORS; i++){
char str[12];
sprintf(str, "%d", floors[i].waitingtogodown + floors[i].waitingtogoup);
print_at_xy(4*NLIFTS+NPEOPLE, NFLOORS-i, " ");
print_at_xy(4*NLIFTS+NPEOPLE, NFLOORS-i, str);
}
}
Sleep(16);
}
// -------------------------------------------------- // --------------------------------------------------
// Main starts the threads and then waits. // Main starts the threads and then waits.
// -------------------------------------------------- // --------------------------------------------------
int main() { int main() {
// Local variables // Local variables
unsigned long i; unsigned long i;
semaphore_create(&printSemaphore, 1); semaphore_create(&printSemaphore, 0);
// Initialise Building // Initialise Building
for(i = 0; i < NFLOORS; i++) { for(i = 0; i < NFLOORS; i++) {
// Initialise Floor // Initialise Floor
floors[i].inprogress_down = 0;
floors[i].inprogress_up = 0;
floors[i].waitingtogoup = 0; floors[i].waitingtogoup = 0;
floors[i].waitingtogodown = 0; floors[i].waitingtogodown = 0;
semaphore_create(&floors[i].up_arrow, 0); semaphore_create(&floors[i].up_arrow, 0);
@ -378,7 +441,7 @@ int main() {
// Create Person Thread // Create Person Thread
create_thread(person_thread, (void*)i); create_thread(person_thread, (void*)i);
} }
//create_thread(update_floor_counts, (void*)i);
// Go to sleep for 86400 seconds (one day) // Go to sleep for 86400 seconds (one day)
Sleep(86400000ULL); Sleep(86400000ULL);
} }

View File

@ -1,20 +1,40 @@
# Logic # Logic
## Details:
***Stylised text in <span style="color:green">green</span> represents the actual lift metaphor***
***<span style="color:red">Red</span> represents significant changes to the program***
## Initial State: ## Initial State:
* Lifts all at the bottom of the building * Lifts all at the bottom of the building
* People all outside the building * People all outside the building
* not waiting on an arrow * not waiting on an arrow
* not in a lift * not in a lift
## State 1: ## Loop:
### *These are performed simulataneously* ### *These are performed simulataneously, with a thread for each instance*
--- ---
* Lift Thread * ### Lift Thread - *this is a black-box as far as the metaphor goes*
1. Lift waits for a short amount of time (to allow people to enter the building) 1. While there are people to unload at this floor, unload them
2. If no one is in the lift, it calls `get_into_lift()` 2. Call `get_into_lift(Lift, Direction)`, to load people from the apporopriate waiting queue (up | down) from the current floor
3. `get_into_lift()` checks if someone is waiting on the up arrow semaphore 3. Redraw
4. Two things must then happen: 3. Change position
* First, the lift must update the lift that currently is on that floor * `get_into_lift()`
* Second, the lift must signal to a passenger that it may enter. 1. Fetch the correct semaphor for our queue
2. Get the number of waiting people on that queue
3. While there are people waiting:
1. If the lift is empty, change our direction to the supplied direction
2. While the lift is not full, and we have people waiting:
* <span style="color:red">Keep track of the number of `in progress` waiting people</span>
1. Add a person to the lift.
2. Redraw the waiting queue
3. Remove the person from the waiting queue
4. Signal person to actually get into the lift
--- ---
* Person Thread * ### Person Thread - *this is modelled around the actual metaphor*
1. 1. Choose a random floor to enter
2. Decide if the floor is above or below the current position
3. Add ourselves to the appropriate move (up | down) group <span style="color:green">Press the `call elevator` button</span>
4. <span style="color:green">Wait for the lift to arrive</span> *on the appropriate spot (up | down); no metaphor for this concept*
5. Enter the lift that is waiting
6. Move to the waiting group for the target floor <span style="color:green">Press the target floor button</span>
7. Wait until the lift reaches our destination floor and leave when it is our turn to exit.