Queuing Up

SMC does not allow a transition to issue a transition itself. The reason for this is explained in SMC's FAQ. But if it is absolutely necessary for you to do so, this section explains how you can do so by creating your own transition queue in C++, Java, Tcl, VB.net and C#.

Warning! The following code assumes that you are not using transition arguments in your code. While it is possible to do transition queuing together with transition arguments, it is more difficult and error prone.


C++ Transition Queue


The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.

(The example code is based on examples/C++/EX1.)

  1. Add a transition enum private member. The enum will contain one entry for each unique transition.
    private: enum Transitions { ZERO_TRANS = 1, ONE_TRANS, UNKNOWN_TRANS, EOS_TRANS };
  2. Add a transition queue private member. Enqueue enum values here for later execution rather the calling the transition methods directly.
    private: Queue<list<int> > _transitionQueue;
  3. Add a private transition method.. This method first places a transition on the queue and, only if it detects this call is outside a transition, dequeues a transition and executes it.
    private: void transition(int transition) { _transitionQueue.push_back(transition); if (_fsm.isInTransition() == false) { while (_transitionQueue.empty() == false) { transition = _transitionQueue.pop_front(); switch (transition) { case ZERO_TRANS: _fsm.Zero(); break; case ONE_TRANS: _fsm.One(); break; case UNKNOWN_TRANS: _fsm.Unknown(); break; case EOS_TRANS: _fsm.EOS(); break; } } } return; }
  4. Replace transition calls. Replace your transition method calls:

    _fsm.Zero();

    with transition method calls:

    transition(ZERO_TRANS)


Java Transition Queue


The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.

(The example code is based on examples/Java/EX1.)

  1. Add a transition table private member. This table is a list of all transition methods. The table is static because the FSM is common for all instances of the context class.
    import java.util.HashMap; ... private static HashMap _transition_map;
  2. Add a transition queue private member. Place transitions here for later execution. One transition queue is needed for each context class instance.
    import java.util.LinkedList; ... private LinkedList _transition_queue;
  3. Find all transition methods. In the class static block, fill in the transition table with the transition methods using Java reflection:
    import java.lang.reflect.Method; ... static { try { Class context = AppClassContext.class; Method[] transitions = context.getDeclaredMethods(); String name; int i; for (i = 0; i < transitions.length; ++i) { name = transitions[i].getName(); // Ignore the getState and getOwner methods. if (name.compareTo("getState") != 0 && name.compareTo("getOwner") != 0) { _transition_map.put(name, transitions[i]); } } } catch (Exception ex) {} }
  4. Add a transition method. Queues up a transition and issues it only if the FSM is not currently in a transition:
    private synchronized void transition(String trans_name) { // Add the transition to the queue. _transition_queue.add(trans_name); // Only if a transition is not in progress should a // transition be issued. if (_fsm.isInTransition() == false) { String name; Method transition; Object[] args = new Object[0]; while (_transition_queue.isEmpty() == false) { name = (String) _transition_queue.remove(0); transition = (Method) _transition_map.get(name); try { transition.invoke(_fsm, args); } catch (Exception ex) { // Handle exception. } } } return; }
  5. Replace transition calls. Replace your transition method calls:

    _fsm.Zero();

    with transition method calls:

    transition("Zero")


Tcl Transition Queues


The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.

(The example code is based on examples/Tcl/EX1.)

  1. Add a transition queue private member. Place transitions here for later execution. One transition queue is needed for each context class instance.
    private variable _transition_queue;
  2. Add a Transition method. Queues up a transition and issues it only if the FSM is not currently in a transition:
    private method Transition {transname} { lappend _transition_queue $transname; if {[$_fsm isInTransition] == 0} { while {[llength $_transition_queue] > 0} { set transition [lindex $_transition_queue 0]; set _transition_queue [lrange $_transition_queue 1 end]; // Issue the transition. $_fsm $transition; } } return -code ok; }
  3. Replace transition calls. Replace your transition method calls:

    $_fsm Zero;

    with transition method calls:

    transition "Zero";


VB.net


The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.

(The examples code is based on examples/VB/EX1.)

  1. Add a transition enum private member. This table is a list of all transition methods. The table is Shared because the FSM is common for all instances of the context class.
    Private Enum Transition As Integer = _ { _ ZERO_TRANS, _ ONE_TRANS, _ UNKNOWN_TRANS, _ EOS_TRANS _ }
  2. Add a transition queue private member. Place transitions here for later execution. One transition queue is needed for each context class instance.
    Imports System.Collections ... Private _transitionQueue As ArrayList
  3. Add a private transition method. This method first places a transition on the queue and executes it only if it detects there is no transition in progress is the specified transition dequeued and executed.
    Private Sub Transition(ByVal transition As Integer) _transitionQueue.Add(transition) While _fsm.IsInTransition = False And _transitionQueue.Count = 0 transition = _transitionQueue.RemoveAt(0) Select Case transition Case Transition.ZERO_TRANS _fsm.Zero() Case Transition.ONE_TRANS _fsm.One() Case Transition.UNKNOWN_TRANS _fsm.Unknown() Case Transition.EOS_TRANS _fsm.EOS() End Select End While End Sub
  4. Replace transition calls. Replace your transition method calls:

    _fsm.Zero()

    with transition method calls:

    transition(Transition.ZERO_TRANS)


C#


The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.

(The examples code is based on examples/CSharp/EX1.)

  1. Add a transition table private member. This table is a list of all transition methods. The table is static because the FSM is common for all instances of the context class.
    using System.Collections; ... private static Hashtable _transition_map;
  2. Add a transition queue private member. Place transitions here for later execution. One transition queue is needed for each context class instance.
    private Queue _transition_queue;
  3. Find all transition methods. In the class static block, fill in the transition table with the transition methods using This method first places a transition on the queue and executes it only if it detects there is no transition in progress is the specified transition dequeued and executed.
    using System.Reflection; ... static AppClass() { try { Type context = Type.GetType("AppClassContext"); MethodInfo[] transitions = context.GetMethods(); string name; int i; for (i = 0; i < transitions.Length; i++) { // Ignore the getState and getOwner methods. if (transitions[i].Name != "getState" && transitions[i].Name != "getOwner") { _transition_map.Add( transitions[i].Name, transitions[i]); } } } catch {} }
  4. Add a transition method. Queues up a transition and issues it only if the FSM is not currently in a transition:
    internal void transition(string trans_name) { lock (_transition_queue) { string name; Method transition; // Add the transition to the queue. _transition_queue.Enqueue(trans_name); // Only if a transition is not in progress should a // transition be issued. while (_fsm.isInTransition() == false && _transition_queue.Count > 0) { name = (string) _transition_queue.Dequeue(); transition = (MethodInfo) _transition_map[name]; try { transition.Invoke(_fsm, null); } catch { // Handle exception. } } } return; }
  5. Replace transition calls. Replace your transition method calls:

    _fsm.Zero()

    with transition method calls:

    transition("Zero")