/******************************************************************* * Sample solutions to Project 1 for CSc33200 * Copyright @ Jinzhong Niu, CS-CCNY, Fall 2003 *******************************************************************/ #include "copyright.h" #include "system.h" Thread CreateThread(char *name, VoidFunctionPtr func, int arg) { Thread th = new Thread(name); th.Fork(func, arg); return th; } /******************************************************************* * Problem 2: Producer/consumer Problem with a circular buffer *******************************************************************/ /** * The definition of the circular buffer, which is actually a MONITOR. */ class Buffer { public: Buffer(); ~Buffer(); void append(char x); char take(); private: int N = 20; char buffer[N]; int nextin, nextout; int count; Condition notfull, notempty; // enforcing the mutual exclusive access to the buffer Lock mutex; } Buffer::Buffer() { count = 0; nextin = 0; nextout = 0; notfull = new Condition("notfull"); noteempty = new Condition("notempty"); mutex = new Lock("mutex"); } Buffer::~Buffer() { delete notfull; delete notempty; delete mutex; } void Buffer::append(char x) { mutex.Acquire(); if (count == N) notfull.Wait(mutex); buffer[nextin] = x; nextin = (nextin + 1) % N; count++; notempty.Signal(mutex); mutex.Release(); } char Buffer::take() { mutex.Acquire(); if (count == 0) notempty.Wait(mutex); x = buffer[nextout]; nextout = (nextout + 1) % N; count--; notfull.Signal(mutex); mutex.Release(); } Buffer buffer = new Buffer(); /** * Procedures for producer and consumer */ void Producer(int id) { char *source = "Hello world"; char *p = source; while (p != NULL) { buffer.append(*p); p++; } } void Consumer(int id) { char x; while (true) { x = buffer.take(); cout << x; } } /** * Main procedure for Problem 2 */ void P2_Producer_Consumer() { CreateThread("producer", Producer, 0); CreateThread("producer", Producer, 1); CreateThread("consumer", Consumer, 0); CreateThread("consumer", Consumer, 1); CreateThread("consumer", Consumer, 2); } /******************************************************************* * Problem 5: Elevator System *******************************************************************/ /** * class Alarm for elevator speed control */ static void AlarmTimerExpired(int arg) { ((Alarm *)arg)->TimerExpired(); } class Alarm { public: Alarm(char* name, VoidFunctionPtr callWhenTimeout, int callArg); ~Alarm(); void GoToSleepFor(int howLong); // should be private, but has to be public // due to the limitation of Nachos void TimerExpired(); private: char *name; bool expired; Thread thread; } Alarm(char* name) { this.name = name; expired = false; } void Alarm::TimerExpired() { ASSERT(thread != NULL); scheduler->ReadyToRun(thread); } void Alarm::GoToSleepFor(int howLong) { interrupt->Schedule(AlarmTimerExpired, (int)this, howLong, TimerInt); thread = currentThread; currentThread->Sleep(); } /** * Variables and Procedures for Elevator and Riders */ static int MAX_FLOORS = 8; Alarm alarm; Semaphore enter_start[MAX_FLOORS]; Semaphore exit_start[MAX_FLOORS]; Semaphore enter_done[MAX_FLOORS]; Semaphore exit_done[MAX_FLOORS]; Semaphore floor_mutex[MAX_FLOORS]; int riders_to_enter[MAX_FLOORS]; int riders_to_exit[MAX_FLOORS]; Semaphore floors_to_stop; int Riders[][] = { {1, 5}, {3, 7}, {3, 1}, {8, 2}, {8, 2}, {8, 7} }; void HasExitRequest(int floor) { bool b; floor_mutex[floor].P(); b = riders_to_exit[floor] > 0; floor_mutex[floor].P(); return b; } void HasEnterRequest(int floor) { bool b; floor_mutex[floor].P(); b = riders_to_enter[floor] > 0; floor_mutex[floor].P(); return b; } int NextRequestedUpperFloor(int floor) { int next_floor = -1; for (int i=floor+1; i=0; i--) { if (HasExitRequest(i) || HasEnterRequest(i)) { next_floor = i; break; } } return next_floor; } void Elevator(int id) { // Inits int direction = 0; int floor = 0; bool exit_requested; bool enter_requested; alarm = new Alarm("ForElevatorSpeedControl"); floors_to_stop = new Semaphore("floors_to_stop", 0); for (int i=0; i=0; i--) { //go down if (direction == -1) next_floor = NextRequestedLowerFloor(floor); // go up else { direction = 1; // in case it is previously 0, then .. next_floor = NextRequestedUpperFloor(floor); } // 1st time, flip the direction; 2nd time, no move if (next_floor == -1) direction *= -1*i; } } // 2. Do what is supposed to do if (next_floor == floor) { floor_mutex[floor].P(); exit_requested = (riders_to_exit[floor] > 0); enter_requested = (riders_to_enter[floor] > 0); if (exit_requested || enter_requested) { cout << "opening door at floor " << floor; } while (riders_to_exit[floor] > 0) { exit_start[floor].V(); exit_done[floor].P(); } while (riders_to_enter[floor] > 0) { enter_start[floor].V(); enter_done[floor].P(); } if (exit_requested || enter_requested) { cout << "closing door at floor " << floor; } floor_mutex[floor].V(); floors_to_stop.P(); } else if (direction != 0) { alarm.GoToSleepFor(200); floor += direction; } } // Clean up delete alarm; delete floors_to_stop; delete [] enter_start; delete [] exit_start; delete [] enter_done; delete [] exit_done; delete [] floor_mutex; } void ArrivingGoingFromTo(int atFloor, int toFloor) { // Requests floor_mutex[atFloor].P(); riders_to_enter[atFloor]++; if (riders_to_enter[atFloor] == 1 && riders_to_exit[atFloor] == 0) { floors_to_stop.V(); } floor_mutex[atFloor].V(); // Enters enter_start[floor].P(); riders_to_enter[floor]--; enter_done[floor].V(); // Desstination request floor_mutex[toFloor].P(); riders_to_exit[toFloor]++; if (riders_to_enter[toFloor] == 0 && riders_to_exit[toFloor] == 1) { floors_to_stop.V(); } floor_mutex[toFloor].V(); // Exits exit_start[floor].P(); riders_to_exit[floor]--; exit_done[floor].V(); } void Rider(int id) { ASSERT((id >= 0) && (id <= riders.length); ASSERT((Riders[id][0] >= 1) && (Riders[id][0] <= MAX_FLOORS)); ASSERT((Riders[id][1] >= 1) && (Riders[id][1] <= MAX_FLOORS)); ASSERT(Riders[id][0] != Riders[id][1]); ArrivingGoingFromTo(Riders[id][0], Riders[id][1]); } /** * Main procedure for Problem 5 */ void P5_ElevatorRiding() { CreateThread("Elevator", Elevator, 0); for (int i=0; i= MAX_NUM_VEHICLES); } void Bridge::Arrive(int direc) { mutex.Acquire(); while (WillCollide(direc)) { number_of_waiting_vehicles[direc]++; green_light[direc].Wait(mutex); } direction = direc; number_of_vehicles++; number_of_waiting_vehicles[direc]--; if (number_of_vehicles < MAX_NUM_VEHICLES) green_light[direc].Signal(mutex); mutex.Release(); } void Bridge::Cross(int direc) { mutex.Acquire(); ASSERT(direction == direc); cout << "crossing the bridge in the direction of " << direc; mutex.Release(); } void Bridge::Exit(int direc) { mutex.Acquire(); ASSERT(direction == direc); number_of_vehicles--; if (number_of_waiting_vehicles[direc] > 0) { green_light[direc].Signal(mutex); } else if (number_of_vehicles == 0) { direction = -1; green_light[(direc + 1) % 2].Signal(mutex); } mutex.Release(); } Bridge bridge = new Bridge(); /** * Procedures for vehicles */ void OneVehicle(int direc) { bridge.Arrive(direc); bridge.Cross(direc); bridge.Exit(direc); } /** * Main procedure for Problem 7 */ void P7_BridgeCrossing() { for (int i=0; i<10; i++) { CreateThread("car", OneVehicle, i % 2); } } /******************************************************************* * Problem 11: QuestionAnswering *******************************************************************/ Semaphore ques_mutex = new Semaphore("ques_mutex", 1); Semaphore ques_avail = new Semaphore("ques_avail", 0); Semaphore answ_avail = new Semaphore("answ_avail", 0); /** * Procedures for student */ void QuestionStart() { ques_mutex.P(); } void QuestionDone() { ques_avail.V(); answ_avail.P(); ques_mutex.V(); } void Student() { while (true) { QuestionStart(); // give a question QuestionDone(); } } /** * Procedures for professor */ void AnswerStart() { ques_avail.P(); } void AnswerDone() { answ_avail.V(); } void Professor() { while (true) { AnswerStart(); // give an answer AnswerDone(); } } /** * Main procedure for Problem 11 */ void P11_QuestionAnswering() { CreateThread("Mr. Professor", Professor); CreateThread("Tom", Student); CreateThread("Jane", Student); CreateThread("Stacey", Student); } /******************************************************************* * Main procedure for Project 1 *******************************************************************/ void ThreadTest() { DEBUG('t', "*****************************************"); DEBUG('t', "* Project 1 by Group n *"); DEBUG('t', "*****************************************"); DEBUG('t', "*****************************************"); DEBUG('t', "* Problem 2 *"); DEBUG('t', "*****************************************"); P2_Producer_Consumer(); DEBUG('t', "*****************************************"); DEBUG('t', "* Problem 5 *"); DEBUG('t', "*****************************************"); P5_ElevatorRiding(); DEBUG('t', "*****************************************"); DEBUG('t', "* Problem 6 *"); DEBUG('t', "*****************************************"); P6_WaterMaking(); DEBUG('t', "*****************************************"); DEBUG('t', "* Problem 7 *"); DEBUG('t', "*****************************************"); P7_BridgeCrossing(); DEBUG('t', "*****************************************"); DEBUG('t', "* Problem 11 *"); DEBUG('t', "*****************************************"); P11_QuestionAnswering(); DEBUG('t', "*****************************************"); DEBUG('t', "* End of output for Project 1 *"); DEBUG('t', "*****************************************"); }