Click here to Skip to main content
15,886,799 members
Articles / Programming Languages / C#

Finite State Machine and Multithreading using .NET

Rate me:
Please Sign up or sign in to vote.
4.79/5 (37 votes)
2 Mar 20068 min read 200.4K   2K   146  
An article on classes for finite state machines, events and threads.
using System;

namespace RTLib
{
	/// <summary>
	/// RTLib is a .NET class library to deal with threads, events and finite state machines (FSMs).
	/// Features:
	/// <list>
	/// <para>-	Supports multi-threading</para> 
	/// <para>-	Supports multiple FSMs on one thread</para> 
	/// <para>-	Supports timer events</para>
	/// <para>-	Allows definition of transition handlers AND / or an event handlers</para> 
	/// <para>- Supports state entry and exit handlers</para> 
	/// <para>-	Allows definition default transition and event handlers</para>
	/// <para>- Minimal effort to write an FSM, less code</para> 
	/// <para>- Flexible through optional usage of attributes</para> 
	/// <para>- Allows one-to-one translation from UML state diagrams</para> 
	/// </list>
	/// <para>During startup, RTLib uses reflection to inspect the user defined classes and creates
	/// event dispatching tables and the bindings to the user-defined handler functions.</para>
	/// 
	/// <para>Implementing an FSM, Step by Step:</para>
	/// <para>1. Derive a class from the RTLib base class Fsm.</para>
	/// <para>   Add a state enumeration type and a state member.</para> 
	/// <para>   Override the GetCurrentState method.</para> 
	/// <para>   Initialize state with the initial state:</para>
	///<code> 
	///public class MyFsm : RTLib.Fsm
	///{
	///  public enum MyState
	///  {
	///     MyState1,
	///     MyState2,
	///     MyState3
	///  };
	///
	///  public MyFsm ()
	///  {
	///    state = MyState.MyState1;
	///  }
	///
	///  private MyState state;
	///
	///  override protected int GetCurrentState()
	///  {
	///    return (int)state;
	///  }
	///}
	///</code>
	///<remarks>
	///The only reason for GetCurrentState() is, that the Fsm class get to know the current state. I did not find a way create it automatically by reflection.
	///</remarks>
	///<para>2. Define your event classes. Every event type is a class derived from the base 
	///class FsmEvent. There exist special event base classes for timer events
	///and synchronizable events.
	///Even it is possible to define them public, they are usually 
	///private to your Fsm as nested classes. Examples:</para>
	///<code>
	///private class MyEvent : RTLib.FsmEvent
	///{
	///  public MyEvent()
	///  {
	///  }
	///}
	///
	///private class MyEventWithParam : RTLib.FsmEvent
	///{
	///  public MyEventWithParam(Param1Type param1)
	///  {
	///    m_Param1 = param1
	///  }
	///
	///  public Param1Type Param1
	///  {
	///    get { return m_Param1;}
	///  }
	///
	///  private Param1Type m_Param1;
	///}
	///
	///private class MyTimerEvent : FsmTimerEvent
	///{
	///  public MyEventA() : base( new TimeSpan(0,0,6) ) // 6 sec
	///  {
	///  }
	///}
	///
	///private class MyAbsoluteTimerEvent : FsmTimerEvent
	///{
	///	public MyEventA()
	///		: base( new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,
	///		        12, 0, 0) ) // Today at noon (12:00:00)
	///	{
	///	}
	///}
	///</code>
	///
	///<para>3. Define your transition-, event- and state handlers.</para>
	///
	///<para>Transition Handler:</para>
	///<para>A method, which is called upon receiving a specific event in a certain state. 
	///Either you can use the naming convention State_Xxxxx(MyEvent) or you can define 
	///a method attribute [FsmTransitionHandler("State")].</para>
	///<para>If you define a transition handler with a event parameter of the base event 
	///class FsmEvent, it is a default transition handler for this state. This can be 
	///used to implement default handling for unexpected events.</para>
	/// 
	///<para>Event Handler:</para>
	///A method, which is called upon receiving a specific event in an FSM without 
	///states or with no transition handler for this event and the current state. 
	///Either you can use the naming convention Xxxxx(MyEvent) or you can define a 
	///method attribute [FsmEventHandler].
	/// 
	///<para>State Handler:</para>
	///A method, which is called upon entering or exit a certain state. Either you 
	///can use the naming convention State_EntryState(), respective State_ExitState() 
	///or you can define a method attribute [FsmStateHandler("State", EStateHandlerType.Entry )],
	///respective [FsmStateHandler("State", EStateHandlerType.Exit )].
	/// 
	///Important note: Attributes can be used only if your FSM class has the following 
	///attribute: [FsmCoding(ECodingType.WithAttributes)]. If you want to suppress 
	///resolution of the naming convention in an FSM without attribute usage, you can 
	///use the method attribute [FsmNoHandler] for any kind of handler method.
	/// 
	///<para>Examples:</para>
	///<code>
	/// // A transition handler
	///private void MyState1_OnMyEventWithParam( MyEventWithParam ev )
	///{
	///  Trace.Write(DateTime.Now+" "+GetType().Name+": ");
	///  Trace.Write("MyState1_OnMyEventWithParam, Param = ");
	///  Trace.WriteLine(ev.Param1);
	///  state = MyState.MyState2;
	///}
	///
	/// // A transition handler with attribute
	///[FsmTransitionHandler("MyState1")]
	///private void TransitionHandlerWithAttribute( MyEvent ev )
	///{
	///  Trace.Write(DateTime.Now+" "+GetType().Name+": ");
	///  Trace.Write("TransitionhandlerWithAttribute");
	///  state = MyState.MyState2;
	///}
	///
	/// // A state handler
	///private void MyState1_EntryState( FsmEvent ev,  State oldState)
	///{
	///  Trace.Write(DateTime.Now+" "+GetType().Name+": ");
	///  Trace.WriteLine("MyState1_EntryState, oldState = "+oldState.ToString() );
	///}
	///
	/// // An event handler
	///private void OnMyEventWithParam( MyEvent ev )
	///{
	///  Trace.Write(DateTime.Now+" "+GetType().Name+": ");
	///  Trace.WriteLine("OnMyEvent");
	///}
	///</code>
	///
	///4. Create an FsmProcessor object and push the FSM to it. If you want to 
	///syncronize to completion of the FSM, add also a Wait() call:
	///<code>
	///FsmProcessor processor = new FsmProcessor("MyProc");
	///MyFsm myFsm = new MyFsm();
	///processor.PushFsm(myFsm);
	///myFsm.Wait();
	///</code>
	///Note: With Wait() it is also possible to synchronize to the 
	///processing of a posted event if it is derived from SyncEvent.
	///Fsm and EventBase have a constructor with a synchronized parameter. 
	///
	///<para>5. There are several ways to terminate the FSM:</para>
	///
	///<para>FSM Internally:</para>
	///<para>In any handler, call the base method TerminateFsm()</para>
	///
	///<para>FSM Externally and FSM Internally:</para>
	///<para>Call Terminate() on Fsm or TerminateFsm(Fsm)on FsmProcessor</para>
	///
	///<para>FSM Externally:</para>
	///<para>Call TerminateAllFsm(delay) on FsmProcessor</para>
	///
	///<para>FSM Entry and Exit Code:</para>
	///When an FSM is posted the thread associated with the FSM processor calls 
	///first the override method OnFsmEntry(). When an FSM terminates 
	///the thread associated with the FSM processor calls the override method OnFsmExit()
	///just before the FSM object is deleted. 
	///By overriding these methods, the user has a 
	///chance to execute some initialization and clean-up code in the context of the 
	///FSM processor thread the FSM is executing on.
	///
	///<para>Event Processing:</para>
	///For performance reasons, all time consuming reflection code is done at start-up time.
	///At runtime, just a few look-ups are necessary to find and call the right handler method.
	///An FSM can have a state variable or not. This has influence to the event 
	///handling. With states, the FSM handles the event in the following order: 
	///<para>With states:</para>
	///<list>
	///<para>Try to dispatch the event to a transition handler</para>
	///<para>If not existing, try to dispatch the event to a default transition handler</para>
	///<para>If not existing, try to dispatch the event to a event handler</para>
	///<para>If not existing, call the default event handler</para>
	///<para>If not overridden, output an error trace</para>
	///</list>
	///<para>Without states:</para>
	///<list>
	///<para>If not existing, try to dispatch the event to a event handler</para>
	///<para>If not existing, call the default event handler</para>
	///<para>If not overridden, output an error trace</para>
	///</list>
	///</summary>
	public class NamespaceDoc
	{
		public NamespaceDoc()
		{
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer Stadt Winterthur
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions