package umontreal.iro.lecuyer.simevents;
import umontreal.iro.lecuyer.simevents.eventlist.EventList;
import umontreal.iro.lecuyer.simevents.eventlist.SplayTree;
import umontreal.iro.lecuyer.simprocs.*;
import java.util.ListIterator;
/**
* Represents the executive of a discrete-event simulator.
* This class maintains a simulation
* clock, an event list, and starts executing the events
* in the appropriate order.
* Its methods permit one to start, stop, and (re)initialize the simulation,
* and read the simulation clock.
*
*
* Usually, a simulation program uses a single simulation clock which is
* represented by an instance of this class.
* For more convenience and compatibility, this class therefore provides
* a mechanism to construct and return a default simulator
* which is used when an event is constructed without an explicit reference to a
* simulator, and when the simulator is accessed through
* the {@link Sim} class.
*
*
* Note that this class is NOT thread-safe. Consequently, if a simulation program
* uses multiple threads, it should acquire a lock on a simulator (using a
* synchronized block) before accessing its state.
* Note however, that one can launch many simulations in parallel with as many
* threads, as long as each thread has its own Simulator.
*
*/
public class Simulator {
protected double currentTime = 0.0;
// The current simulation time (clock).
protected EventList eventList;
// The list of future events.
// Can be changed by the method \texttt{init}.
protected boolean stopped = true;
// Becomes true when the simulation has ended
// (stopped has been called or the event list is empty).
protected boolean simulating = false;
protected ContinuousState continuousState = null;
/**
* Represents the default simulator being used by the
* class {@link Sim}, and the no-argument constructor of {@link Event}.
* This simulator is usually obtained with the
* {@link #getDefaultSimulator getDefaultSimulator} method, which initializes it if needed.
* But it might also be initialized
* differently, e.g., if process-driven simulation is required.
*
*/
public static Simulator defaultSimulator = null;
/**
* Constructs a new simulator using a splay tree for the
* event list.
*
*/
public Simulator() {
eventList = new SplayTree();
}
/**
* Constructs a new simulator using eventList for
* the event list.
*
*/
public Simulator (EventList eventList) {
if (eventList == null)
throw new NullPointerException();
this.eventList = eventList;
}
/**
* Returns the current value of the simulation clock.
* @return the current simulation time
*
*/
public double time()
{
return currentTime;
}
/**
* Reinitializes the simulation executive by clearing up the event
* list, and resetting the simulation clock to zero.
*
*/
public void init() {
// This has to be done another way in order to separate events and processes.
// SimProcess.killAll();
currentTime = 0.0; eventList.clear(); stopped = false; simulating = false;
}
/**
* Same as {@link #init init}, but also chooses evlist as the
* event list to be used.
* For example, init (new DoublyLinked()) initializes the simulation
* with a doubly linked linear structure for the event list. To initialize the
* current Simulator with a not empty eventList is also possible, but
* the events scheduled in the eventList will be linked with the current simulator only.
*
* @param evlist selected event list implementation
*
*
*/
public void init (EventList evlist) {
if (evlist == null)
throw new NullPointerException();
eventList = evlist;
ListIterator iter = eventList.listIterator();
while(iter.hasNext())
((Event)iter.next()).setSimulator(this);
init();
}
/**
* Gets the currently used event list.
*
* @return the currently used event list
*
*/
public EventList getEventList() {
return eventList;
}
/**
* Determines if this simulator is currently running, i.e.,
* executing scheduled events.
*
*/
public boolean isSimulating() {
return simulating;
}
/**
* Determines if this simulator was stopped by
* an event. The simulator may still be processing the event which
* has called the {@link #stop stop} method; in this case,
* {@link #isSimulating isSimulating} returns true.
*
*/
public boolean isStopped() {
return stopped;
}
/**
* Removes the first event from the event list and sets the simulation
* clock to its event time.
*
* @return the first planned event, or null if there is no such event
*
*/
protected Event removeFirstEvent() {
if (stopped)
return null;
Event ev = eventList.removeFirst();
if (ev == null)
return null;
currentTime = ev.eventTime;
ev.eventTime = -10.0;
return ev;
}
/**
* Starts the simulation executive.
* There must be at least one Event in the
* event list when this method is called.
*
*/
public void start () {
if (eventList.isEmpty())
throw new IllegalStateException ("start() called with an empty event list");
stopped = false;
simulating = true;
Event ev;
try {
while ((ev = removeFirstEvent()) != null && !stopped) {
// while (!stopped && (ev = eventList.removeFirst()) != null) {
// currentTime = ev.eventTime;
// ev.eventTime = -10.0;
ev.actions();
// if ev is a thread object associated to a process,
// the control will be transfered to this thread and the
// executive will be passivated in the actions() method.
}
}
finally {
stopped = true; simulating = false;
}
}
/**
* Tells the simulation executive to stop as soon as it takes control,
* and to return control to the program that called {@link #start start}.
* This program will then continue executing from the instructions right after
* its call to {@link #start(.) start} If an {@link Event} is currently executing (and
* this event has just called {@link #stop stop}), the executive will take
* control when the event terminates its execution.
*
*/
public void stop()
{
stopped = true;
}
/**
* Returns the current state of continuous variables being
* integrated during the simulation.
* This state is used by the {@link Continuous} class when performing
* simulation of continuous variables; it defaults to an empty state,
* which is initialized only when this method is called.
*
* @return continuousState field
*
*/
public ContinuousState continuousState()
{
if (continuousState == null)
continuousState = new ContinuousState(this);
return continuousState;
}
/**
* Returns the default simulator instance used by
* the deprecated class {@link Sim}.
* If this simulator does not exist yet, it is constructed using the
* no-argument constructor of this class.
* One can specify a different default simulator by setting
* the defaultSimulator field directly.
*
*/
public static Simulator getDefaultSimulator() {
if (defaultSimulator == null)
defaultSimulator = new Simulator();
return defaultSimulator;
}
}
Ads help maintain this website.