using System; using System.Threading; using Wayne.Lib.Log; namespace Wayne.Lib.StateEngine { /// /// Threaded root state machine is the class that is driving a normal asynchronous state machine. It /// contains the logic for running a statemachine in a separate thread. /// //[System.Diagnostics.DebuggerNonUserCode()] internal class ThreadedRootStateMachine : EventBufferingRootStateMachine { #region Fields private System.Threading.Thread thread; private AutoResetEvent eventReceivedEvent = new AutoResetEvent(false); private AutoResetEvent threadStartedEvent = new AutoResetEvent(false); private bool threadTerminated; #endregion #region Construction /// /// Initializes a new instance of the ThreadedRootStateMachine class. /// /// The name of the statemachine. /// The DebugLogger to use. /// The log category. public ThreadedRootStateMachine(string name, IDebugLogger debugLogger, object logCategory) : base(name, debugLogger, logCategory) { thread = new System.Threading.Thread(new System.Threading.ThreadStart(Execute)); } #endregion #region Private methods /// /// Thread method. /// private void Execute() { try { Initialize(); PerformInitialTransition(); //Signal to the thread calling Start() that it can continue to execute. threadStartedEvent.Set(); CreateOnStateChangeEventHandler(this); while (!threadTerminated) { //Wait for new event to be added to the queue. eventReceivedEvent.WaitOne(); if (!threadTerminated) { //Read out the event HandleQueuedEvents(null); } } } catch (Exception exception) { throw new StateEngineException(string.Format("Unexpected Exception in Execute(). StateMachine \"{0}\"", this.Name), exception); } } #endregion #region Public Methods /// /// Entry point for incoming events. The base functionality is removed, and moved into the thread. /// This method only puts the message into the event list, and signals to the thread that a new event has been added. /// /// public override void IncomingEvent(StateEngineEvent stateEngineEvent) { //Base EventBufferingRootStateMachine takes care of queueing the event. base.IncomingEvent(stateEngineEvent); //Signal to the thread that there is a new event to handle. if (eventReceivedEvent != null) eventReceivedEvent.Set(); } /// /// Starts the state machine. The base functionality is removed and moved to the thread. /// public override void Start() { //Start the thread thread.Name = this.Name; thread.Start(); //Wait until the thread is really started and initialized. threadStartedEvent.WaitOne(); } #endregion #region Protected Methods /// /// Disposes the resources owned by the instance. /// /// protected override void Dispose(bool disposing) { if (!disposed) { this.threadTerminated = true; eventReceivedEvent.Set(); if (this.Started) { // JDL, MAR-02-10, wait up to 1 sec if (!thread.Join(1000)) thread.Abort(); thread = null; } if (eventReceivedEvent != null) { eventReceivedEvent.Close(); eventReceivedEvent = null; } if (threadStartedEvent != null) { threadStartedEvent.Close(); threadStartedEvent = null; } } base.Dispose(disposing); } #endregion } }