umontreal.iro.lecuyer.simprocs.SimProcess Maven / Gradle / Ivy
Show all versions of ssj Show documentation
/*
* Class: SimProcess
* Description: Abstract class providing process scheduling tools
* Environment: Java
* Software: SSJ
* Copyright (C) 2001 Pierre L'Ecuyer and Université de Montréal
* Organization: DIRO, Université de Montréal
* @author
* @since
* SSJ is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License (GPL) as published by the
* Free Software Foundation, either version 3 of the License, or
* any later version.
* SSJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* A copy of the GNU General Public License is available at
GPL licence site.
*/
package umontreal.iro.lecuyer.simprocs;
import umontreal.iro.lecuyer.simevents.Event;
import umontreal.iro.lecuyer.simevents.eventlist.EventList;
import umontreal.iro.lecuyer.simevents.Simulator;
import umontreal.iro.lecuyer.simprocs.ProcessSimulator;
/**
* This abstract class provides process scheduling tools.
* Each type of process should be defined as a subclass of the
* class SimProcess, and must provide an implementation of the method
* {@link #actions actions} which describes the life of a process of this class.
* Whenever a process instance starts, its {@link #actions actions} method
* begins executing.
*
*
* Just like an event, a process must first be constructed, then scheduled.
* Scheduling a process is equivalent to placing an event in the event list
* that will start this process when
* the simulation clock reaches the specified time.
* The {@link #toString toString} method can be overridden to return
* information about the process. This information will
* be returned when formating the event list as a string, if the
* process is delayed.
*
*
* A process can be in one of the following states: INITIAL,
* EXECUTING, DELAYED, SUSPENDED, and DEAD
* .
* At most one process can be in the EXECUTING state at
* any given time, and when there is one, this executing process
* (called the current process) is said to have control
* and is executing one of the instructions of its {@link #actions actions} method.
* A process that has been constructed but not yet scheduled is in
* the INITIAL state.
* A process is in the DELAYED state if there is a planned event
* in the event list to activate it (give it control).
* When a process is scheduled, it is placed in the DELAYED state.
* It is in the SUSPENDED state if it is waiting to be reactivated
* (i.e., obtain control) without having an event to do so in the event list.
* A process can suspends itself by calling {@link #suspend suspend} directly or
* indirectly (e.g., by requesting a busy {@link Resource}).
* Usually, a SUSPENDED process must be reactivated by another process
* or event via the {@link #resume resume} method.
* A process in the DEAD state no longer exists.
*
*
* To construct new processes, the user needs to extend {@link SimProcess}.
*
*
* Note: the user needs to ensure that the actions
* method of any process can be terminated, i.e., no infinite loops.
* For example, using threads process-oriented simulator,
* if such a method never terminates, threads will not be recycled,
* causing memory problems.
*
*/
public class SimProcess {
/**
* The process has been created but not yet scheduled.
*
*/
public static final int INITIAL = 0;
/**
* The process is the one currently executing its
* {@link #actions actions} method.
*
*/
public static final int EXECUTING = 1;
/**
* The process is not executing but has an event in the event list to
* reactivate it later on.
*
*/
public static final int DELAYED = 2;
/**
* The process is not executing and will have to be reactivated by another
* process or event later on.
*
*/
public static final int SUSPENDED = 3;
/**
* The process has terminated its execution.
*
*/
public static final int DEAD = 4;
// The state of a process is not kept explicitly, but
// can be recovered from its eventTime variable.
public static final double STARTING = -20.0;
public static final double WAITING = -10.0;
// Variables
protected ProcessSimulator sim;
// Simulator linked with this simProcess.
protected Event scheduledEvent = null;
// the next scheduled event
/**
* Constructs a new process without scheduling it
* and associates this new process with the default simulator; one
* can get additional knowledge with
* {@link umontreal.iro.lecuyer.simevents.Simulator Simulator} static methods.
* It will have to be scheduled later on.
* The process is in the INITIAL state.
*
*/
public SimProcess() {
this((ProcessSimulator)Simulator.getDefaultSimulator());
}
/**
* Constructs a new process associated with sim
* without scheduling it. It will have to be scheduled later on.
* The process is in the INITIAL state.
*
* @param sim Link the current variable to ProcessSimulator sim
*
*/
public SimProcess (ProcessSimulator sim) {
this.sim = sim;
scheduledEvent = sim.createControlEvent(this);
}
/**
* Schedules the process to start in delay time units.
* This puts the process in the DELAYED state.
*
* @param delay delay, in simulation time, before the process starts
*
*
*/
public void schedule (double delay) {
if (scheduledEvent == null)
throw new IllegalStateException ("Cannot schedule a dead process");
if (scheduledEvent.time() != STARTING)
throw new IllegalStateException ("Only a process in INITIAL state can call schedule");
scheduledEvent.schedule (delay);
}
/**
* Schedules this process to start at the current time, by placing
* it at the beginning of the event list.
* This puts the process in the DELAYED state.
*
*/
public void scheduleNext() {
if (scheduledEvent == null)
throw new IllegalStateException ("Cannot schedule a dead process");
if (scheduledEvent.time() != STARTING)
throw new IllegalStateException
("Only a process in INITIAL state can call scheduleNext");
scheduledEvent.scheduleNext();
}
/**
* Returns the Event associated with the current variable.
*
*/
public Event scheduledEvent() {
return scheduledEvent;
}
/**
* Sets the event associated to the current variable.
*
* @param scheduledEvent new scheduledEvent for the current variable
*
*
*/
public void setScheduledEvent (Event scheduledEvent) {
this.scheduledEvent = scheduledEvent;
}
/**
* Returns the priority of the current variable.
*
* @return priority of the current variable.
*
*/
public double priority() {
return scheduledEvent.priority();
}
/**
* Sets the priority assigned to the current variable in the simulation.
* This method should never be called after the event has been scheduled, otherwise
* the events will not execute in ascending priority order anymore.
*
* @param priority priority assigned to the current variable in the simulation
*
*
*/
public void setPriority (double priority) {
scheduledEvent.setPriority(priority);
}
/**
* Returns true if the process is alive, otherwise false.
*
* @return true if the process is not in the DEAD state
*
*/
public final boolean isAlive() {
return scheduledEvent != null;
}
/**
* Returns the state of the process.
*
* @return one of the process states {@link #INITIAL INITIAL},
* {@link #EXECUTING EXECUTING}, {@link #DELAYED DELAYED}, {@link #SUSPENDED SUSPENDED}, or
* {@link #DEAD DEAD}.
*
*/
public int getState() {
if (scheduledEvent == null) return DEAD;
else if (sim.currentProcess() == this) return EXECUTING;
else if (scheduledEvent.time() >= 0.0) return DELAYED;
else if (scheduledEvent.time() == STARTING) return INITIAL;
else return SUSPENDED;
}
/**
* If the process is in the DELAYED state, returns
* the remaining time until the planned occurrence of its
* activating event.
* Otherwise, an illegal state exception will be thrown printing an error message.
*
* @return remaining delay before the process starts
* @exception IllegalStateException if the process is not in DELAYED state
*
*
*/
public double getDelay() {
if (scheduledEvent == null)
throw new IllegalStateException ("Trying to getDelay() on a dead process");
if (scheduledEvent.time() < 0.0)
throw new IllegalStateException
("Calling getDelay for a process not in DELAYED state");
return scheduledEvent.time() - sim.time();
}
/**
* If the process is in the DELAYED state, removes it from
* the event list and reschedules it in delay units of time.
* Example: If the process p has called {@link #delay delay}(5.0)
* at time 10.0, and another process invokes {@link #reschedule reschedule}(p, 6.2)
* at time 13.5, then the process p will resume at time
*
* 13.5 + 6.2 = 19.7.
*
* @param delay new delay, in simulation time units, before the process starts or is resumed
*
*
*/
public void reschedule (double delay) {
if (sim.currentProcess() == this)
throw new IllegalStateException
("reschedule() for a process in EXECUTING state");
if (scheduledEvent == null)
throw new IllegalStateException ("reschedule() for a dead process ");
if (delay < 0.0) throw new IllegalArgumentException
("Calling reschedule() with negative delay");
scheduledEvent.reschedule (delay);
}
/**
* Places this process at the beginning of the event list
* to resume its execution. If the process was DELAYED, cancels
* its earlier activating event.
*
*/
public void resume() {
if (scheduledEvent == null) // DEAD state
throw new IllegalStateException ("calling resume() for a dead process");
if (scheduledEvent.time() >= 0.0) scheduledEvent.cancel();
scheduledEvent.scheduleNext();
}
/**
* Cancels the activating event that was supposed to resume
* this process, and places the process in the SUSPENDED state.
* This method can be invoked only for a process in the DELAYED
* state.
*
* @return true if the process was canceled successfully
*
*/
public boolean cancel() {
if (scheduledEvent == null) // DEAD state
throw new IllegalStateException ("calling cancel() for a dead process");
if (scheduledEvent.time() < 0.0 )
throw new IllegalStateException
("cancel() for a process not in DELAYED state");
boolean removed = scheduledEvent.cancel();
scheduledEvent.setTime (WAITING);
return removed;
}
/**
* Suspends the execution of the currently executing process and
* schedules it to resume its execution in delay units of simulation
* time. It moves in the DELAYED state.
* Only the process in the EXECUTING state can call this method.
*
*/
public void delay (double delay) {
sim.delay(this, delay);
}
/**
* This method can only be invoked for the EXECUTING
* or a DELAYED process.
* If the process is EXECUTING, suspends execution.
* If the process is DELAYED, cancels its activating event.
* This places the process in the SUSPENDED state.
*
*/
public void suspend() {
sim.suspend(this);
}
/**
* Terminates the life of this process and sets its state to
* DEAD, after canceling its activating event if there is one.
*
*/
public void kill() {
sim.kill(this);
}
/**
* This is the method that is called when this process is
* executing. Every subclass of SimProcess that is to be
* instantiated must provide an implementation of this method.
*
*/
public void actions() { };
/**
* This method calls ProcessSimulator.initDefault(),
* which initializes the default simulator to use processes.
*
*/
public static void init() {
ProcessSimulator.initDefault();
}
}