AsyncWorkState.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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.Threading;
  24. namespace Wayne.Lib.StateEngine.Generic
  25. {
  26. /// <summary>
  27. /// Generic state that enables descendant classes to execute code on a worker thread
  28. /// when the state is active. When the processing is completed, i.e. the PerformWork returns,
  29. /// the state will post a transition of the type specified in the constructor.
  30. ///
  31. /// When exitting the state, we for the worker thread to complete before continuing.
  32. ///
  33. /// Descendant classes can also use the AbortWork() method to signal to the worker thread that it should exit as fast as possible.
  34. ///
  35. /// The PerformWork method should periodically check the Aborted property and if that is true, exit as fast as possible.
  36. /// </summary>
  37. /// <typeparam name="TMain"></typeparam>
  38. public abstract class AsyncWorkState<TMain> : State<TMain>
  39. {
  40. #region Fields
  41. bool aborted;
  42. object doneTransitionType;
  43. object runningLock = new object();
  44. #endregion
  45. #region Construction
  46. /// <summary>
  47. /// Initializes a new instance of the AsyncWorkState class.
  48. /// </summary>
  49. protected AsyncWorkState(object doneTransitionType)
  50. {
  51. this.doneTransitionType = doneTransitionType;
  52. }
  53. #endregion
  54. #region Methods
  55. /// <summary>
  56. /// Called when entering the state.
  57. /// </summary>
  58. /// <param name="stateEntry"></param>
  59. /// <param name="transition"></param>
  60. protected override void Enter(Wayne.Lib.StateEngine.StateEntry stateEntry, ref Wayne.Lib.StateEngine.Transition transition)
  61. {
  62. base.Enter(stateEntry, ref transition);
  63. if (transition == null)
  64. {
  65. aborted = false;
  66. ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), null);
  67. }
  68. }
  69. private void DoWork(object o)
  70. {
  71. try
  72. {
  73. try
  74. {
  75. if (aborted)
  76. return;
  77. lock (runningLock)
  78. {
  79. PerformWork();
  80. }
  81. }
  82. catch (Exception e)
  83. {
  84. if ((ParentStateMachine.debugLogger != null) && ParentStateMachine.debugLogger.IsActive())
  85. ParentStateMachine.debugLogger.Add(e);
  86. }
  87. }
  88. finally
  89. {
  90. this.ParentStateMachine.IncomingEvent(new StateEngineEvent(GenericEventType.AsyncDone));
  91. }
  92. }
  93. /// <summary>
  94. /// Called when exitting the state.
  95. /// </summary>
  96. protected override void Exit()
  97. {
  98. base.Exit();
  99. aborted = true;
  100. lock (runningLock)
  101. {
  102. }
  103. }
  104. /// <summary>
  105. /// Handles events.
  106. /// </summary>
  107. /// <param name="stateEngineEvent"></param>
  108. /// <param name="transition"></param>
  109. protected override void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
  110. {
  111. base.HandleEvent(stateEngineEvent, ref transition);
  112. if (stateEngineEvent.Type.Equals(GenericEventType.AsyncDone))
  113. {
  114. stateEngineEvent.Handled = true;
  115. WorkDone(ref transition);
  116. }
  117. }
  118. /// <summary>
  119. /// Method that is called when the work is done. Override to specify another transition type than the one
  120. /// specified in the constructor.
  121. /// </summary>
  122. /// <param name="transition"></param>
  123. protected virtual void WorkDone(ref Transition transition)
  124. {
  125. transition = new Transition(this, doneTransitionType);
  126. }
  127. /// <summary>
  128. /// Signals to the thread that it should exit as quick as possible. Can be overridden by descendant
  129. /// classes to create user code to abort.
  130. /// </summary>
  131. protected virtual void AbortWork()
  132. {
  133. aborted = true;
  134. }
  135. /// <summary>
  136. /// Signals that the PerformWork method should return as fast as possible.
  137. /// </summary>
  138. protected bool Aborted { get { return aborted; } }
  139. #endregion
  140. #region Abstract methods
  141. /// <summary>
  142. /// Method that is called in a worker thread.
  143. /// </summary>
  144. protected abstract void PerformWork();
  145. #endregion
  146. }
  147. }