Click or drag to resize
StaMaEvent Driven and Scan Cycle Driven State Machines

Explains typical approaches how to execute a state machine within a thread.

Running a state machine means checking for enabled transitions. The check can either be triggered when an event arrives or can be done periodically. In case the check identifies an enabled transition, the transition must be executed. In order to ensure consistency within the state machine, all checking and excution of transitions has to be done sequentially. The most natural approach is to run this within a single thread to avoid synchronization and locking within the state machine.

In StaMa transition checking and excution of transitions is triggered through the StateMachine.SendTriggerEvent method. StaMa is intended for the single threaded approach and explicitly omits usage of runtime system synchronisation mechanisms like locks, monitors, mutexes, semaphores or whatever may exist. Provided that proper synchronization mechanisms are in place, it would in principle be possible to run every single invocation of SendTriggerEvent in an arbitrary thread, however it is strongly recommended to execute SendTriggerEvent always in the same thread to avoid confusing execution of the actions from varying threads.

Different state machine instances may be run in the same or individual threads, as needed.

Often the state machine can be executed in the main thread while asynchronous operation requests, triggered through the actions, are executed in background threads and call back into the main thread when they are completed.

The StateMachine.SendTriggerEvent method runs an entire run-to-completion cycle which means that this method synchronously checks for an enabled transition and executes the transition in a loop until the state machine has reached a stable state where no further transitions are enabled.

As suggested initially, there are two major strategies how to trigger checking for transitions of a state machine:

  • Event driven state machines evaluate the state machine only when an event arrives. Applications with a significant amount of asynchronous operations usually use this mode of operation.

  • Cycle driven state machines periodically evaluate the state machine at a fixed time interval. This mode is particularly useful to coordinate the activation of binary or analog, open or closed loop controllers in programmable logic controller (PLC) like applications. Such loop controller state machines typically utilize state specific do-actions which are executed in every cycle to calculate the current controller output variables.

Mixtures of these strategies are possible, e.g. an event driven state machine might regularly check for elapsed timeouts of transitions or other changes.

 

Event driven state machine operation

Event driven state machines are typically executed in a message driven thread.

Typical message driven threads in .NET Windows Desktop Framework applications are the UI main threads.

For WinForms the Application.Run methods start a message loop. Messages can be sent to the thread using the SynchronizationContext.Post method of the SynchronizationContext instance returned through the SynchronizationContext.Current property of the message loop thread.

For WPF the Application.Run methods internally start the Dispatcher.Run method. Messages can be sent to the thread using the Dispatcher.InvokeAsync methods on the Dispatcher instance returned through Dispatcher.FromThread or through the Dispatcher property of most WPF related objects.

In .NET Micro Framework applications the Dispatcher.Run method executes a message loop. Messages can be sent to the thread using the Dispatcher.BeginInvoke method of the Dispatcher instance returned through Dispatcher.FromThread or through the Dispatcher property of objects that inherit from DispatcherObject.

Definitely there are many other ways to set up a thread that runs a message loop, eventually more performant, however the easiest way is to reuse existing base library functionality.

 

Cycle driven state machine operation

Cycle driven state machines are usually a part of a control system. They are executed in a thread that regularly activates itself in a loop. A single loop of such a control system typically consists of reading the input from sensors, executing the logic and driving the actors. The logic execution is (at least partially) implemented through a state machine that is typically solely based on guard conditions at the transitions. The guard conditions evaluate the input from the sensors, while the entry and exit actions drive the actors.

Entry and exit actions of a state machine are only executed during state transitions, however open or closed loop control circuits need to respond to changes of the sensors and do work while the state machine stays in a state. In order to facilitate this mode, so called do actions can be assigned to the states of the state machine, and the do actions are executed without a state change e.g. as part of the regular check for transitions.

StaMa supports this model of state machine operation through the StateMachineTemplate.State method overload that allows to specify a do action and and through the StateMachineTemplate(StateMachineOptions.UseDoActions) constructor that enables the do action processing within the SendTriggerEvent method.

Do actions must be enabled explicitly as they cause an additional check for active transitions within every call to SendTriggerEvent. This is because executing the do actions may cause a change in variables used by guard conditions or may enqueue an event which has to be checked as part of the run-to-completion processing. Event driven state machines don't need do actions, thus the small performance disadvantage can be avoided by only explicitly enabling do actions.

See also Introductory PLC Programming for a short description how programmable logic controllers work.