Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
//: C20:BankTeller.cpp // Using a queue and simulated multithreading // To model a bank teller system #include <iostream> #include <queue> #include <list> #include <cstdlib> #include <ctime> 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<Customer>& customers; Customer current; static const int slice = 5; int ttime; // Time left in slice bool busy; // Is teller serving a customer? public: Teller(queue<Customer>& 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<Customer> { public: friend ostream& operator<<(ostream& os, const CustomerQ& cd) { copy(cd.c.begin(), cd.c.end(), ostream_iterator<Customer>(os, "")); return os; } }; int main() { CustomerQ customers; list<Teller> tellers; typedef list<Teller>::iterator TellIt; tellers.push_back(Teller(customers)); srand(time(0)); // Seed random number generator while(true) { // 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 } } } ///:~