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
}
}