![]() |
VR-Link API Documentation for HLA Evolved
|
This is a simple example to test and show VR-Link's threading classes.
This example is composed of several classes, and several functions. The central function is called runTest().
/****************************************************************************** ** Copyright (c) 1992-2010 VT MAK ** All rights reserved. ******************************************************************************/ #include <stdlib.h> #include <time.h> #include <stdio.h> #include <iostream> #include <set> #include <stack> #include <vlutil/vlThreadSafe.h> #include <vlutil/vlRunnable.h> #include <vlutil/vlThreadedObject.h> #include <vlutil/vlMutex.h> #include <vlutil/vlProcessControl.h> DtMutex iomutex; // Thread safe print for functions. void print_ts(const char* msg) { DtScopedLock lock(iomutex); std::cout << msg << std::endl; } class Restaurant; class Customer; class Order; class Food; typedef DtThreadSafe<std::set<Customer*> > CustomerSet; typedef DtThreadSafe<std::stack<Order> > OrderStack; typedef DtThreadSafe<std::stack<Food> > FoodStack; // Utility resource classes class Order { public: int timeToCook; Customer* theCustomer; }; class Food { public: int timeToEat; }; // Restaurant functions as a consumer and producer of food. It takes in // customers and as it receives orders it make the food and serves it. Upon // the last customer leaving, the restaurant closes. class Restaurant : public DtRunnable { public: Restaurant(); // Executes the run virtual void run(); // Public thread safe interface // A customer orders food. void orderFood(Order order); // A customer enters. void enter(Customer* customer); // A customer leavs. void leave(Customer* customer); protected: // Internal operations // Check to see if there are any customers. // \retval true NO customers are in. // \retval false Customers are in. bool noCustomers(); // Takes an order. Order takeOrder(); // Makes food for an order. Food makeFood(Order order); // Waits for a little bit. void takeBreak(); // Close the restaurant. void close(); protected: CustomerSet myCustomers; OrderStack myOrders; }; class Customer : public DtRunnable { public: // Create a customer, who goes to a restaurant. Customer(const char* name,int time,Restaurant* res); // Executes the run virtual void run(); // Public thread safe interface // Food is served to the customer. void serveFood(Food food); // Get name const char* name() const; protected: // Internal operations // Order food. void orderFood(); // Waits until the customer received food. void waitForFood(); // Customer eats food. void eatFood(); // Customer leaves restaurant. void leave(); protected: const char* myName; int myTime; FoodStack myFoodStack; Restaurant* myRestaurant; }; Customer::Customer(const char* name,int time,Restaurant* res) : myName(name), myTime(time), myFoodStack(std::stack<Food>()), myRestaurant(res) { res->enter(this); } void Customer::run() { orderFood(); waitForFood(); eatFood(); leave(); }; const char* Customer::name() const { return myName; } void Customer::orderFood() { char buffer[256]; sprintf(buffer,"%s: ordering food.",myName); print_ts(buffer); Order order; order.timeToCook = myTime; order.theCustomer = this; myRestaurant->orderFood(order); } void Customer::waitForFood() { while(myFoodStack->size() == 0) DtSleep(.5); } void Customer::eatFood() { Food food = myFoodStack->top(); myFoodStack->pop(); for(int i = 0;i < food.timeToEat;++i) { char buffer[256]; sprintf(buffer,"%s: Eating for %d",myName,i); print_ts(buffer); DtSleep(0.5); } } void Customer::serveFood(Food food) { myFoodStack->push(food); } void Customer::leave() { char buffer[256]; sprintf(buffer,"%s: leaving restaurant",myName); print_ts(buffer); myRestaurant->leave(this); } Restaurant::Restaurant() : myOrders(std::stack<Order>()), myCustomers(std::set<Customer*>()) { } void Restaurant::run() { //Run until told to stop or no more customers while(true) { if(noCustomers()) { close(); return; } //Take an order, Make the food Order order = takeOrder(); if(order.theCustomer != 0) { Food meal = makeFood(order); print_ts("Restaurant: Serving food"); order.theCustomer->serveFood(meal); } else { takeBreak(); } } close(); } bool Restaurant::noCustomers() { return myCustomers->size() == 0; } void Restaurant::orderFood(Order order) { myOrders->push(order); } Order Restaurant::takeOrder() { Order order; order.theCustomer = 0; {//Scope for sequence lock DtScopedSequenceLock lock = myOrders.sequenceLock(); if(myOrders->size() > 0) { order = myOrders->top(); myOrders->pop(); print_ts("Restaurant: Took Order"); } } return order; } Food Restaurant::makeFood(Order order) { char buffer[256]; int totalTime = order.timeToCook; while(totalTime > 0) { sprintf(buffer,"Restaurant: Making food: Finished in %d s",totalTime); print_ts(buffer); --totalTime; DtSleep(1); } Food food; food.timeToEat = order.timeToCook * 2; return food; } void Restaurant::leave(Customer* customer) { myCustomers->erase(customer); } void Restaurant::enter(Customer* customer) { char buffer[256]; sprintf(buffer,"Restaurant: Seeting %s",customer->name()); print_ts(buffer); myCustomers->insert(customer); } void Restaurant::takeBreak() { print_ts("Restaurant: Taking 5"); DtSleep(5); } void Restaurant::close() { print_ts("Restaurant: Closing"); } void RunTest() { const char* customerNames[] = { "Colin", "Jim", "Len", "Howard", "Mike", "Karen", "Jeff", "Jeff", "Ben", "Rob", "Marshal", "Doug", "Aline", "Nate", "Fred", "Jorge" }; int customerCount = 16; time_t t = time(NULL); srand(t); Restaurant* aRestaurant = new Restaurant(); DtThreadedObject thread0(DtRunnableSP( (DtRunnable*)aRestaurant)); Customer* customer1 = new Customer(customerNames[rand() % customerCount],2,aRestaurant); DtThreadedObject thread1(DtRunnableSP( (DtRunnable*)customer1)); Customer* customer2 = new Customer(customerNames[rand() % customerCount],3,aRestaurant); DtThreadedObject thread2(DtRunnableSP((DtRunnable*)customer2)); Customer* customer3 = new Customer(customerNames[rand() % customerCount],4,aRestaurant); DtThreadedObject thread3(DtRunnableSP((DtRunnable*)customer3)); Customer* customer4 = new Customer(customerNames[rand() % customerCount],5,aRestaurant); DtThreadedObject thread4(DtRunnableSP((DtRunnable*)customer4)); Customer* customer5 = new Customer(customerNames[rand() % customerCount],6,aRestaurant); DtThreadedObject thread5(DtRunnableSP((DtRunnable*)customer5)); // Start all threads executing. thread0.start(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); // Wait for all customers thread1.join(); thread2.join(); thread3.join(); thread4.join(); thread5.join(); // Wait for restaurant. thread0.join(); } int main(int argc, char* argv[]) { RunTest(); }