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