VR-Link API Documentation for DIS
Threading Example

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();
}


Document ID: Generated on Mon May 14 08:06:18 EDT 2012 from SVN revision 114750
Copyright © 2005-2012 VT MÄK Inc. All Rights Reserved (www.mak.com)