Mostly sorted
This commit is contained in:
parent
ed6cc593b6
commit
33752ca3a1
@ -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);
|
||||||
}
|
}
|
||||||
|
42
logic.md
42
logic.md
@ -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.
|
Loading…
x
Reference in New Issue
Block a user