//: C07:BankTeller.cpp {RunByHand} // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) 1995-2004 MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at www.MindView.net. // Using a queue and simulated multithreading // to model a bank teller system. #include #include #include #include #include #include using namespace std; class Customer { int serviceTime; public: Customer() : serviceTime(0) {} Customer(int tm) : serviceTime(tm) {} int getTime() { return serviceTime; } void setTime(int newtime) { serviceTime = newtime; } friend ostream& operator<<(ostream& os, const Customer& c) { return os << '[' << c.serviceTime << ']'; } }; class Teller { queue& customers; Customer current; enum { SLICE = 5 }; int ttime; // Time left in slice bool busy; // Is teller serving a customer? public: Teller(queue& cq) : customers(cq), ttime(0), busy(false) {} Teller& operator=(const Teller& rv) { customers = rv.customers; current = rv.current; ttime = rv.ttime; busy = rv.busy; return *this; } bool isBusy() { return busy; } void run(bool recursion = false) { if(!recursion) ttime = SLICE; int servtime = current.getTime(); if(servtime > ttime) { servtime -= ttime; current.setTime(servtime); busy = true; // Still working on current return; } if(servtime < ttime) { ttime -= servtime; if(!customers.empty()) { current = customers.front(); customers.pop(); // Remove it busy = true; run(true); // Recurse } return; } if(servtime == ttime) { // Done with current, set to empty: current = Customer(0); busy = false; return; // No more time in this slice } } }; // Inherit to access protected implementation: class CustomerQ : public queue { public: friend ostream& operator<<(ostream& os, const CustomerQ& cd) { copy(cd.c.begin(), cd.c.end(), ostream_iterator(os, "")); return os; } }; int main() { CustomerQ customers; list tellers; typedef list::iterator TellIt; tellers.push_back(Teller(customers)); srand(time(0)); // Seed the random number generator clock_t ticks = clock(); // Run simulation for at least 5 seconds: while(clock() < ticks + 5 * CLOCKS_PER_SEC) { // Add a random number of customers to the // queue, with random service times: for(int i = 0; i < rand() % 5; i++) customers.push(Customer(rand() % 15 + 1)); cout << '{' << tellers.size() << '}' << customers << endl; // Have the tellers service the queue: for(TellIt i = tellers.begin(); i != tellers.end(); i++) (*i).run(); cout << '{' << tellers.size() << '}' << customers << endl; // If line is too long, add another teller: if(customers.size() / tellers.size() > 2) tellers.push_back(Teller(customers)); // If line is short enough, remove a teller: if(tellers.size() > 1 && customers.size() / tellers.size() < 2) for(TellIt i = tellers.begin(); i != tellers.end(); i++) if(!(*i).isBusy()) { tellers.erase(i); break; // Out of for loop } } } ///:~