Tech Note

Title:               Pause and Resume Functionality in the Executive
Date:              July 1, 2007
Written by:     Peter Bosch
Number:        TN-018
Version:         1.0

At the heart of a simulation is the executive. The executive manages a list of requested callbacks, often called the “event queue.” It provides temporal coordination of all activities in the simulation, and presents the current simulation time to the application containing the simulation.

Creating/Obtaining an Executive

An executive is selected in the context of a model by obtaining it from the ExecFactory. The Sage® libraries offer two simulation executives, each of which implements Highpoint.Sage.SimCore.IExecutive. An Executive (an implementer of IExecutive) is created by any of the following 4 code constructs. Note that the example which obtains exec4a obtains it as a reference to an already-created Executive for which we already know the Guid.

 

// using Highpoint.Sage.SimCore;

 

// Obtain an executive of the default type and unspecified Guid from the factory.

IExecutive exec1 = ExecFactory.Instance.CreateExecutive();

// ... or ...

// Obtain an executive of the default type and specified Guid from the factory.

IExecutive exec2 = ExecFactory.Instance.CreateExecutive(Guid.NewGuid());

// ... or ...

// Obtain an executive of the specified type and Guid from the factory.

IExecutive exec3 = ExecFactory.Instance.CreateExecutive("Highpoint.Sage.SimCore.Executive",

                                                        Guid.NewGuid());

// ... or ...

// Obtain an executive of the specified type and Guid from the factory.

IExecutive exec4 = ExecFactory.Instance.CreateExecutive("Highpoint.Sage.SimCore.Executive3",

                                                        Guid.NewGuid());

 

// and on the odd chance that you have the exec's guid but not its instance ...

IExecutive exec4a = ExecFactory.Instance.GetExecutive(exec4.Guid);

 

The default executive type is specified in the Sage section of the App.config file, as shown below. In the Sage section shown below, the ExecutiveType entry specifies that the Highpoint.Sage.SimCore.Executive3 type is to be used by default. If no entry is present, the framework assumes that you want the Highpoint.Sage.SimCore.Executive type.

       <configSections>   

             <section name="Sage"

                      type="System.Configuration.NameValueSectionHandler,System,Version=1.0.3300.0,

                            Culture=neutral,PublicKeyToken=b77a5c561934e089" />

       </configSections>

       <Sage>

              <add key="ExecutiveType" value="Highpoint.Sage.SimCore.Executive3"/>

       </Sage>

Note that the Sage section has been edited down to only this element, for brevity.

Available Executives and Their Features

There are currently two executives provided. They are described below:

Highpoint.Sage.SimCore.Executive

This is a full-featured executive, with rescindable and detachable events, support for pause and resume and event priority sorting within the same timeslice, and detection of causality violations. Use FastExecutive if these features are unimportant and you want blistering speed. This class cannot be inherited.

Highpoint.Sage.SimCore.Executive3

(FYI: to be renamed FastExecutive in a near-future release).

This executive is to be used if speed, more speed, and even more speed are the top three priorities of your project. In the vast majority of situations, the features you lose will cost you far more than the speed you will gain. Feel free to contact Highpoint to discuss it if you think you might need this one.

This is a very fast executive, designed for applications in which raw speed is the greatest and most overriding concern. This executive accomplishes this goal without rescindable or detachable events, support for pause and resume, event priority sorting within the same timeslice, or detection of causality violations. Use the Executive class if these features are important and you are willing to sacrifice a little bit of speed to get them. Note that if you are doing anything non-trivial in your event handlers, this 'sacrifice' quickly becomes unnoticeable. This class cannot be inherited.

Controlling the Executive

A model’s executive should not be managed directly, but inside a Model’s State Machine. This accepts Model start, stop, pause, resume, initialize, validate, etc. functions to be performed. It allows correlation of executive stops, ModelObject resets, log flushing, data logging, and many other functions at the model level using a simple API. A default state machine comes with the default Model class, but the user may design arbitrarily complex state machines relatively easily. This will be the subject of another TechNote. Having said this, we now describe how (presumably within such a state machine) the executive is controlled.

Starting and Ending an Executive

Once obtained, an executive can be started by calling myExecutive.Start(); Note that the executive runs on the caller’s thread. This can cause some surprising effects if it is run, for example, on the GUI thread in a button-push handler. Thread separation is advisable.

If there is at least one non-daemon event (see below) in the executive’s event queue, that event will run. If, during its running, that event’s handler submits more events to the executive, the simulation will continue to run until there are no more non-daemon events in the queue, or until it is stopped or paused.

An executive is stopped overtly by calling myExecutive.Stop();.

Pausing and Resuming an Executive

Recall that the executive runs on the caller’s thread. Assuming that you have separated that thread from the GUI thread, you will be able to click a pause button, and have a GUI that responds with a call to a handler for that button. In that handler (or other situations, depending on the mechanism being used, the application will have a thread available to call myExecutive.Pause() while the simulation is running.

The effect of a pause call into the executive is to set a flag (a monitor) that will block the main thread that is running the executive, and cause it to transition the executive’s state to Paused. The thread that called pause will return immediately. The transition to pause will happen the next time the operating system allows the executive’s main thread to run. As a result, the thread that called Pause may not immediately see the executive in the paused state.

A call by a thread into the myExecutive.Resume() method does the opposite – it releases the monitor so that the next time the executive’s main thread gets a timeslice, it will transition the executive to “Running” and resume.

Rescinding Events

When a request is made to register an event, a number (a long) is returned to the caller. This is the event’s ID number. Assuming the event has not already been serviced, it may be removed from the event queue using that number, the specific delegate, or the object to which that delegate was attached.

The following snippet of code illustrates this mechanism.

long eventID = exec.RequestEvent(

                    new ExecEventReceiver(myObject.SomeCallback),

                    when,

                    priority,

                    userData,

                    execEventType);

 

. . . L a t e r   I n   t h e   c o d e . . .

 

// Rescind the object with this event ID.

exec.UnRequestEvent(eventID);

 

// Rescind all events that call into the SomeCallback method on the myObject.

exec.UnRequestEvents(new ExecEventReceiver(myObject.SomeCallback));

 

// Rescind all events that call into the myObject object.

exec.UnRequestEvents(myObject);

 

A fourth, more advanced mechanism exists for event rescinding. The API

void UnRequestEvents(IExecEventSelector ees);

Can be used with an implementer of the IExecEventSelector interface. In this situation, the ees object will be allowed to review all events and decide based on arbitrary logic, if that event is to be rescinded. This interface is documented in the help file.

 

Event Types

Event types are used to select the way the Executive dispatches an event once its time has arrived.

 These mechanisms are as follows:

 Synchronous – the callback is called on the dispatch thread, and upon completion, the next callback is selected based upon scheduled time and priority.

 Detachable – the callback is called on a thread from the .Net thread pool, and the dispatch thread then suspends awaiting the completion or suspension of that thread. If the event thread is suspended, an event controller is made available to other entities which can be used to resume or abort that thread. This is useful for modeling “intelligent entities” and situations where the developer wants to easily represent a delay or interruption of a process.

Asynchronous - This mechanism is not yet supported. It represents a fire-and-forget style of event, useful for writing log data, or other I/O-intensive operations. Note – Jan-Willem, if you need this, please let me know. It’s simple to implement, but no one has wanted it yet.

Daemon Events

Daemon events are submitted through the following API

RequestDaemonEvent(ExecEventReceiver eer, DateTime when, double priority, object userData);

(details in the help file). Daemon events are events that will be executed, but cannot, by themselves, keep the executive running. Thus, as soon as the event queue contains no non-daemon threads, it will stop.

This event type is useful for managing event streams such as equipment failure calendars, correlate-to-real-time simulation run-speed throttling, and others.

Causality Violations

A causality violation occurs when, for example, the current time (myExecutive.Now) is 5/16/2004, 5:13PM, and the application requests an event to occur at 5/13/2004, 3:27 AM. An event running on a Sunday wants to cause something to happen the preceding Thursday.