sim-din
In
In this section, we will briefly discuss the
SIM library, as an example of object-oriented support
for discrete event simulation.
See The SIM library
The scheduling algorithm extracts all events with the same activation time. It activates the events in priority order with the highest scheduling priority first. Before executing the events, the simulation clock is updated to the activation time of the current events. Furthermore, a FIFO conditional list (containing events that occur when some condition is met) is traversed in priority order with highest scheduling priority first. Events that can run now are executed. Events that are not used anymore should be terminated to prevent the system from overflow.
In slide sim-event a state-diagram is given,
which depicts the states (see slide sim-states) an event object can be in.
The state of an event can be affected both by the scheduler
as well as from within the user-defined methods of the event.
The labels on the arrows indicate the methods that
result in a state transition. (As a convention, the methods
above the arrows indicate a transition from left to right,
the methods below the arrow a transition from right to left,
in case of a bi-directional relation between states.)
Example -- dining philosophers
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;
}
(C) Æliens 04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.