We will now look at two methods to define the actual
simulation mode, an event-based method and
a process-based method.
The event-based approach
We develop this program in the following steps. First, the library is included as sim.h. The declarations of the
global variables and constants follow after that. The time unit in this simulation is an hour, so a philosopher has
a mean eating time of two hours and a mean thinking time of five hours. The duration of the simulation is a
year. After that, we define the various events.
a year
const int number = 5; philosophers
const int eatingtime = 2; 2 hours
const int thinkingtime = 5; 5 hours
simulation* sim;
generator* g;
resource* chopstick[number];
histogram* thinking;
constructor, taking identity
virtual int operator()(); function operator
private :
int id; identity of the philosopher
};
class think : public event
{
public :
think(int i); constructor, taking identity
virtual int operator()(); function operator
private :
int id; identity of the philosopher
};
class await : public event
{
public :
await(int i); constructor, taking identity
virtual int operator()(); function operator
private :
int id; identity of the philosopher
};
The logic of the eat event is that the philosopher eats for a random time, exponentially distributed with a mean
eating time. So, we first determine the actual eating time and schedule a think event to be activated after this
eating time. The eat event can be terminated.
set identity
}
int eat::operator()()
{
double t = g -> exponential(eatingtime); eating time
think* th = new think(id); create a thinking event
sim -> schedule(th,t); schedule thinking
sim -> terminate(this); terminate this eat event
return OK;
}
set identity
}
int think::operator()()
{
chopstick[id] -> release(); release left chopstick
chopstick[(id+1) % number] -> release(); release right
double t = g -> exponential(thinkingtime); thinking time
thinking -> sample(id,t/duration*100); add a sample (%)
await* aw = new await(id); create await event
sim -> schedule(aw,t); schedule waiting
sim -> terminate(this); terminate thinking
return OK;
}
set identity
}
int await::operator()()
{
if ( (chopstick[id] -> available()) && available ?
(chopstick[(id+1) % number] -> available()) )
{
chopstick[id] -> acquire(); acquire left
chopstick[(id+1) % number] -> acquire(); acquire right
eat* e = new eat(id);
sim -> passivate(this); extract from conditional list
sim -> schedule(e,0); schedule eat event immediately
sim -> terminate(this); terminate await event
}
else if (!conditional()) not on conditional list
sim -> hold(this); add to conditional list
return OK;
}
tk is an instance variable of session
{
sim = new simulation();
g = new generator(80,20,19); gets three seeds
thinking = new histogram(".h","-columns 5 -title thinkingtime");
tk -> pack(thinking); add to display;
tk -> update(); update display;
for (int i=0;i
await* aw = new await(i); schedule each
sim -> schedule(aw,0); philosopher waiting
}
sim -> run(duration); run for duration
cout << (*thinking) << endl; print resulting histogram
delete thinking;
delete sim;
return 0; successful termination
}
The process-oriented approach
The entity class is derived from the event class. It may be regarded as a compound event, that is it maintains an additional phase variable to record the actual phase it is in.
We first identify the entities (or the types) in the model. The events are represented as methods of an entity.
The function operator calls these events based on the phase the entity is in, as illustrated in the definition of a philosopher.
phases of a philosopher
class philosopher : public entity
{
public :
philosopher(int ph,int i); constructor, taking phase and id
virtual int operator()(); function operator
int eat(); eat event
int think(); think event
int await(); await event
private :
int id;
generator* g;
};
philosopher::philosopher(int ph,int i) : entity(ph)
{
id = i; set phase and identity
g = new generator(20,10,999);
}
int philosopher::operator()()
{
switch (phase()) what phase is the philosopher in?
{
case EATING :
return eat(); the philosopher eats
case THINKING :
return think(); the philosopher thinks
case WAITING :
return await(); the philosopher waits
}
return FALSE;
}
int philosopher::eat()
{
double t = g -> exponential(eatingtime); determine eating time
sim -> wait(t); schedule this philosopher thinking
phase(THINKING); set phase to thinking
return OK;
}
int philosopher::think()
{
chopstick[id] -> release(); release left chopstick
chopstick[(id+1) % number] -> release(); release right
double t = g -> exponential(thinkingtime); determine thinking time
thinking -> sample(id,t/duration*100); sample (%)
sim -> wait(t); schedule this philosopher waiting
phase(WAITING); set phase on waiting
return OK;
}
int philosopher::await()
{
if ( (chopstick[id] -> available()) && available?
(chopstick[(id+1) % number] -> available()) )
{
chopstick[id] -> acquire(); acquire left chopstick
chopstick[(id+1) % number] -> acquire(); acquire right
sim -> passivate(this); make passive
sim -> activate(this); activate as eating
phase(EATING); set phase on eating
}
else if (!conditional())
sim -> hold(this); add to conditional
return OK;
}