AsyncWorkState.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #region --------------- Copyright Dresser Wayne Pignone -------------
  2. /*
  3. * $Log: /Wrk/WayneLibraries/Wrk/StateEngine/Generic/AsyncWorkState.cs $
  4. *
  5. * 5 08-03-25 10:32 Mattias.larsson
  6. * Ensure debugLogger is not null.
  7. *
  8. * 4 07-11-28 15:40 roger.månsson
  9. *
  10. * 3 07-10-23 13:47 roger.månsson
  11. * Must protect the access to the field currentWork, or there may be race
  12. * conditions, the field is maybe not be assigned until after the work is
  13. * done for example.
  14. *
  15. * 2 07-10-17 13:20 roger.månsson
  16. * Made publicly available. Added overridable method WorkDone.
  17. *
  18. * 1 07-03-27 9:33 roger.månsson
  19. * Created.
  20. */
  21. #endregion
  22. using System;
  23. using System.Collections.Generic;
  24. using Wayne.Lib;
  25. using Wayne.Lib.StateEngine;
  26. using System.Threading;
  27. namespace Wayne.Lib.StateEngine.Generic
  28. {
  29. /// <summary>
  30. /// Generic state that enables descendant classes to execute code on a worker thread
  31. /// when the state is active. When the processing is completed, i.e. the PerformWork returns,
  32. /// the state will post a transition of the type specified in the constructor.
  33. ///
  34. /// When exitting the state, we for the worker thread to complete before continuing.
  35. ///
  36. /// Descendant classes can also use the AbortWork() method to signal to the worker thread that it should exit as fast as possible.
  37. ///
  38. /// The PerformWork method should periodically check the Aborted property and if that is true, exit as fast as possible.
  39. /// </summary>
  40. /// <typeparam name="TMain"></typeparam>
  41. public abstract class AsyncWorkState<TMain> : State<TMain>
  42. {
  43. #region Fields
  44. bool aborted;
  45. object doneTransitionType;
  46. object runningLock = new object();
  47. #endregion
  48. #region Construction
  49. /// <summary>
  50. /// Initializes a new instance of the AsyncWorkState class.
  51. /// </summary>
  52. protected AsyncWorkState(object doneTransitionType)
  53. {
  54. this.doneTransitionType = doneTransitionType;
  55. }
  56. #endregion
  57. #region Methods
  58. /// <summary>
  59. /// Called when entering the state.
  60. /// </summary>
  61. /// <param name="stateEntry"></param>
  62. /// <param name="transition"></param>
  63. protected override void Enter(Wayne.Lib.StateEngine.StateEntry stateEntry, ref Wayne.Lib.StateEngine.Transition transition)
  64. {
  65. base.Enter(stateEntry, ref transition);
  66. if (transition == null)
  67. {
  68. aborted = false;
  69. ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), null);
  70. }
  71. }
  72. private void DoWork(object o)
  73. {
  74. try
  75. {
  76. try
  77. {
  78. if (aborted)
  79. return;
  80. lock (runningLock)
  81. {
  82. PerformWork();
  83. }
  84. }
  85. catch (Exception e)
  86. {
  87. if ((ParentStateMachine.debugLogger != null) && ParentStateMachine.debugLogger.IsActive())
  88. ParentStateMachine.debugLogger.Add(e);
  89. }
  90. }
  91. finally
  92. {
  93. this.ParentStateMachine.IncomingEvent(new StateEngineEvent(GenericEventType.AsyncDone));
  94. }
  95. }
  96. /// <summary>
  97. /// Called when exitting the state.
  98. /// </summary>
  99. protected override void Exit()
  100. {
  101. base.Exit();
  102. aborted = true;
  103. lock (runningLock)
  104. {
  105. }
  106. }
  107. /// <summary>
  108. /// Handles events.
  109. /// </summary>
  110. /// <param name="stateEngineEvent"></param>
  111. /// <param name="transition"></param>
  112. protected override void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
  113. {
  114. base.HandleEvent(stateEngineEvent, ref transition);
  115. if (stateEngineEvent.Type.Equals(GenericEventType.AsyncDone))
  116. {
  117. stateEngineEvent.Handled = true;
  118. WorkDone(ref transition);
  119. }
  120. }
  121. /// <summary>
  122. /// Method that is called when the work is done. Override to specify another transition type than the one
  123. /// specified in the constructor.
  124. /// </summary>
  125. /// <param name="transition"></param>
  126. protected virtual void WorkDone(ref Transition transition)
  127. {
  128. transition = new Transition(this, doneTransitionType);
  129. }
  130. /// <summary>
  131. /// Signals to the thread that it should exit as quick as possible. Can be overridden by descendant
  132. /// classes to create user code to abort.
  133. /// </summary>
  134. protected virtual void AbortWork()
  135. {
  136. aborted = true;
  137. }
  138. /// <summary>
  139. /// Signals that the PerformWork method should return as fast as possible.
  140. /// </summary>
  141. protected bool Aborted { get { return aborted; } }
  142. #endregion
  143. #region Abstract methods
  144. /// <summary>
  145. /// Method that is called in a worker thread.
  146. /// </summary>
  147. protected abstract void PerformWork();
  148. #endregion
  149. }
  150. }