From 33752ca3a1f66a7541258ee1b5d5bfa7b5f9f69d Mon Sep 17 00:00:00 2001 From: Brychan Dempsey Date: Tue, 27 Apr 2021 20:34:24 +1200 Subject: [PATCH] Mostly sorted --- assignment2_handout.c | 127 +++++++++++++++++++++++++++++++----------- logic.md | 42 ++++++++++---- 2 files changed, 126 insertions(+), 43 deletions(-) diff --git a/assignment2_handout.c b/assignment2_handout.c index 3ffd2b5..a978c71 100644 --- a/assignment2_handout.c +++ b/assignment2_handout.c @@ -11,24 +11,35 @@ // -------------------------------------------------- // 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 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 delay times (in milliseconds) // -------------------------------------------------- -#define SLOW -// #define FAST - -#if defined(SLOW) - #define LIFTSPEED 50 // The time it takes for the lift to move one floor - #define GETINSPEED 50 // The time it takes to get into the lift - #define GETOUTSPEED 50 // The time it takes to get out of the lift +//#define SUPERSLOW +//#define SLOW + //#define FAST + #define SUPERFAST +#if defined(SUPERSLOW) + #define LIFTSPEED 500 // The time it takes for the lift to move one floor + #define GETINSPEED 250 // The time it takes to get into 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 #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 GETINSPEED 0 // The time it takes to get into 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 down_arrow; // People going down wait on this 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; // -------------------------------------------------- @@ -62,7 +77,10 @@ typedef struct { int peopleinlift; // The number of people in the lift int stops[NFLOORS]; // How many people are going to each floor 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; // -------------------------------------------------- @@ -78,11 +96,11 @@ semaphore printSemaphore; // Print a string on the screen at position (x,y) // -------------------------------------------------- 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); // Move cursor to (x,y) gotoxy(x,y); - // Slow things down Sleep(1); @@ -91,6 +109,7 @@ void print_at_xy(int x, int y, const char *s) { // Move cursor out of the way gotoxy(42, NFLOORS+2); + // flush the stream and release the semaphore fflush(stdout); 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) { // Local variables - int *waiting; + volatile int *waiting; + volatile int *inprogress; semaphore *s; // Check lift direction @@ -111,14 +131,18 @@ void get_into_lift(lift_info *lift, int direction) { // Number of people waiting to go up waiting = &floors[lift->position].waitingtogoup; + inprogress = &floors[lift->position].inprogress_up; } else { // Use down_arrow semaphore s = &floors[lift->position].down_arrow; // Number of people waiting to go down 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 while(*waiting) { // Check if lift is empty @@ -127,24 +151,36 @@ void get_into_lift(lift_info *lift, int direction) { lift->direction = direction; } - // Check there are people waiting and lift isn't full - if(lift->peopleinlift < MAXNOINLIFT && *waiting) { + // Check there are people waiting and lift isn't full. Ignore in-progress (moving into lift) people + // 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 - semaphore_wait(&lift->load); lift->peopleinlift++; - semaphore_signal(&lift->load); - - // Erase the person from the waiting queue - print_at_xy(NLIFTS*4+floors[lift->position].waitingtogodown + floors[lift->position].waitingtogoup, NFLOORS-lift->position, " "); - + 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 + //semaphore_signal(&floors[lift->position].queueInteraction); + // Do the print, no need to hold the semaphore while this is going on + // One less person waiting + // Note that while loading, the queue cannot change + //semaphore_wait(&floors[lift->position].queueInteraction); + (*waiting)--; + (*inprogress)--; + semaphore_signal(&floors[lift->position].queueInteraction); + // Wait for person to get into lift Sleep(GETINSPEED); targetLift[lift->position] = lift; semaphore_signal(s); } else { + semaphore_signal(&floors[lift->position].queueInteraction); break; } } @@ -164,8 +200,9 @@ void* lift_thread(void *p) { lift.position = 0; // Lift starts on ground floor lift.direction = UP; // Lift starts going up lift.peopleinlift = 0; // Lift starts empty - - semaphore_create(&lift.load, 1); + // lift is ok with loading a single person + semaphore_create(&lift.loading, 1); + semaphore_create(&lift.buttonPress, 1); for(i = 0; i < NFLOORS; i++) { lift.stops[i]=0; // No passengers waiting @@ -182,19 +219,21 @@ void* lift_thread(void *p) { while(TRUE) { // Print current position of the lift print_at_xy(no*4+1, NFLOORS-lift.position, lf); - // Wait for a while Sleep(LIFTSPEED); // Drop off passengers on this floor while (lift.stops[lift.position] != 0) { // One less passenger in lift - semaphore_wait(&lift.load); + semaphore_wait(&lift.loading); lift.peopleinlift--; - + semaphore_signal(&lift.loading); // 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]--; - semaphore_signal(&lift.load); + semaphore_signal(&lift.buttonPress); + // Wait for exit lift delay Sleep(GETOUTSPEED); @@ -205,6 +244,7 @@ void* lift_thread(void *p) { if(!lift.stops[lift.position]) { // Clear the "-" print_at_xy(no*4+1+2, NFLOORS-lift.position, " "); + } } // Check if lift is going up or is empty @@ -260,6 +300,7 @@ void* person_thread(void *p) { if(to > from) { // One more person waiting to go up 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); // Print person waiting print_at_xy(NLIFTS*4+ floors[from].waitingtogoup +floors[from].waitingtogodown,NFLOORS-from, pr); @@ -268,9 +309,11 @@ void* person_thread(void *p) { } else { // One more person waiting to go down 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); // 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; // Wait for a lift to arrive (going down) } @@ -283,9 +326,9 @@ void* person_thread(void *p) { // Add one to passengers waiting for floor // Only one person enters at a time - semaphore_wait(&lift->load); + semaphore_wait(&lift->buttonPress); lift->stops[to]++; - semaphore_signal(&lift->load); + semaphore_signal(&lift->buttonPress); // Press button if we are the first if(lift->stops[to]==1) { // Print light for destination @@ -313,7 +356,6 @@ void printbuilding(void) { // Clear Screen system(clear_screen); // Print the whole building before anything else - semaphore_wait(&printSemaphore); // Print Roof printf("%s", tl); for(l = 0; l < NLIFTS-1; l++) { @@ -342,19 +384,40 @@ void printbuilding(void) { printf("Lift Simulation - Press CTRL-Break to exit\n"); // Ensure buffer is written fflush(stdout); + // Once the building has been printed, then we can those waiting to print that they may do so 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. // -------------------------------------------------- int main() { // Local variables unsigned long i; - semaphore_create(&printSemaphore, 1); + semaphore_create(&printSemaphore, 0); // Initialise Building for(i = 0; i < NFLOORS; i++) { // Initialise Floor + floors[i].inprogress_down = 0; + floors[i].inprogress_up = 0; floors[i].waitingtogoup = 0; floors[i].waitingtogodown = 0; semaphore_create(&floors[i].up_arrow, 0); @@ -378,7 +441,7 @@ int main() { // Create Person Thread create_thread(person_thread, (void*)i); } - + //create_thread(update_floor_counts, (void*)i); // Go to sleep for 86400 seconds (one day) Sleep(86400000ULL); } diff --git a/logic.md b/logic.md index 9c90a87..7636f0e 100644 --- a/logic.md +++ b/logic.md @@ -1,20 +1,40 @@ # Logic +## Details: +***Stylised text in green represents the actual lift metaphor*** + +***Red represents significant changes to the program*** ## Initial State: * Lifts all at the bottom of the building * People all outside the building * not waiting on an arrow * not in a lift -## State 1: -### *These are performed simulataneously* +## Loop: +### *These are performed simulataneously, with a thread for each instance* --- -* Lift Thread - 1. Lift waits for a short amount of time (to allow people to enter the building) - 2. If no one is in the lift, it calls `get_into_lift()` - 3. `get_into_lift()` checks if someone is waiting on the up arrow semaphore - 4. Two things must then happen: - * First, the lift must update the lift that currently is on that floor - * Second, the lift must signal to a passenger that it may enter. +* ### Lift Thread - *this is a black-box as far as the metaphor goes* + 1. While there are people to unload at this floor, unload them + 2. Call `get_into_lift(Lift, Direction)`, to load people from the apporopriate waiting queue (up | down) from the current floor + 3. Redraw + 3. Change position +* `get_into_lift()` + 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: + * Keep track of the number of `in progress` waiting people + 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 - 1. \ No newline at end of file +* ### Person Thread - *this is modelled around the actual metaphor* + 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 Press the `call elevator` button + 4. Wait for the lift to arrive *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 Press the target floor button + 7. Wait until the lift reaches our destination floor and leave when it is our turn to exit. \ No newline at end of file