#region --------------- Copyright Dresser Wayne Pignone -------------
/*
* $Log: /Wrk/WayneLibraries/Wrk/StateEngine/Generic/AsyncWorkState.cs $
*
* 5 08-03-25 10:32 Mattias.larsson
* Ensure debugLogger is not null.
*
* 4 07-11-28 15:40 roger.månsson
*
* 3 07-10-23 13:47 roger.månsson
* Must protect the access to the field currentWork, or there may be race
* conditions, the field is maybe not be assigned until after the work is
* done for example.
*
* 2 07-10-17 13:20 roger.månsson
* Made publicly available. Added overridable method WorkDone.
*
* 1 07-03-27 9:33 roger.månsson
* Created.
*/
#endregion
using System;
using System.Collections.Generic;
using Wayne.Lib;
using Wayne.Lib.StateEngine;
using System.Threading;
namespace Wayne.Lib.StateEngine.Generic
{
///
/// Generic state that enables descendant classes to execute code on a worker thread
/// when the state is active. When the processing is completed, i.e. the PerformWork returns,
/// the state will post a transition of the type specified in the constructor.
///
/// When exitting the state, we for the worker thread to complete before continuing.
///
/// Descendant classes can also use the AbortWork() method to signal to the worker thread that it should exit as fast as possible.
///
/// The PerformWork method should periodically check the Aborted property and if that is true, exit as fast as possible.
///
///
public abstract class AsyncWorkState : State
{
#region Fields
bool aborted;
object doneTransitionType;
object runningLock = new object();
#endregion
#region Construction
///
/// Initializes a new instance of the AsyncWorkState class.
///
protected AsyncWorkState(object doneTransitionType)
{
this.doneTransitionType = doneTransitionType;
}
#endregion
#region Methods
///
/// Called when entering the state.
///
///
///
protected override void Enter(Wayne.Lib.StateEngine.StateEntry stateEntry, ref Wayne.Lib.StateEngine.Transition transition)
{
base.Enter(stateEntry, ref transition);
if (transition == null)
{
aborted = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), null);
}
}
private void DoWork(object o)
{
try
{
try
{
if (aborted)
return;
lock (runningLock)
{
PerformWork();
}
}
catch (Exception e)
{
if ((ParentStateMachine.debugLogger != null) && ParentStateMachine.debugLogger.IsActive())
ParentStateMachine.debugLogger.Add(e);
}
}
finally
{
this.ParentStateMachine.IncomingEvent(new StateEngineEvent(GenericEventType.AsyncDone));
}
}
///
/// Called when exitting the state.
///
protected override void Exit()
{
base.Exit();
aborted = true;
lock (runningLock)
{
}
}
///
/// Handles events.
///
///
///
protected override void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
{
base.HandleEvent(stateEngineEvent, ref transition);
if (stateEngineEvent.Type.Equals(GenericEventType.AsyncDone))
{
stateEngineEvent.Handled = true;
WorkDone(ref transition);
}
}
///
/// Method that is called when the work is done. Override to specify another transition type than the one
/// specified in the constructor.
///
///
protected virtual void WorkDone(ref Transition transition)
{
transition = new Transition(this, doneTransitionType);
}
///
/// Signals to the thread that it should exit as quick as possible. Can be overridden by descendant
/// classes to create user code to abort.
///
protected virtual void AbortWork()
{
aborted = true;
}
///
/// Signals that the PerformWork method should return as fast as possible.
///
protected bool Aborted { get { return aborted; } }
#endregion
#region Abstract methods
///
/// Method that is called in a worker thread.
///
protected abstract void PerformWork();
#endregion
}
}