Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Core/3.2/EngineBase.cs @ 2879

Last change on this file since 2879 was 2474, checked in by swagner, 15 years ago

Implemented generic EventArgs (#796)

File size: 14.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Xml;
26using System.Threading;
27using HeuristicLab.Common;
28
29namespace HeuristicLab.Core {
30  /// <summary>
31  /// Base class to represent an engine, which is an interpreter, holding the code, the data and
32  /// the actual state, which is the runtime stack and a pointer onto the next operation. It represents
33  /// one execution and can handle parallel executions.
34  /// </summary>
35  public abstract class EngineBase : ItemBase, IEngine {
36    /// <summary>
37    /// Field of the current instance that represent the operator graph.
38    /// </summary>
39    protected IOperatorGraph myOperatorGraph;
40    /// <summary>
41    /// Gets the current operator graph.
42    /// </summary>
43    public IOperatorGraph OperatorGraph {
44      get { return myOperatorGraph; }
45    }
46    /// <summary>
47    /// Field of the current instance that represent the global scope.
48    /// </summary>
49    protected IScope myGlobalScope;
50    /// <summary>
51    /// Gets the current global scope.
52    /// </summary>
53    public IScope GlobalScope {
54      get { return myGlobalScope; }
55    }
56
57    private TimeSpan myExecutionTime;
58    /// <summary>
59    /// Gets or sets the execution time.
60    /// </summary>
61    /// <remarks>Calls <see cref="OnExecutionTimeChanged"/> in the setter.</remarks>
62    public TimeSpan ExecutionTime {
63      get { return myExecutionTime; }
64      protected set {
65        myExecutionTime = value;
66        OnExecutionTimeChanged();
67      }
68    }
69
70    private ThreadPriority myPriority;
71    /// <summary>
72    /// Gets or sets the priority of the worker thread.
73    /// </summary>
74    public ThreadPriority Priority {
75      get { return myPriority; }
76      set { myPriority = value; }
77    }
78
79    /// <summary>
80    /// Field of the current instance that represent the execution stack.
81    /// </summary>
82    protected Stack<IOperation> myExecutionStack;
83    /// <summary>
84    /// Gets the current execution stack.
85    /// </summary>
86    public Stack<IOperation> ExecutionStack {
87      get { return myExecutionStack; }
88    }
89   
90    /// <summary>
91    /// Flag of the current instance whether it is currently running.
92    /// </summary>
93    protected bool myRunning;
94    /// <summary>
95    /// Gets information whether the instance is currently running.
96    /// </summary>
97    public bool Running {
98      get { return myRunning; }
99    }
100
101    /// <summary>
102    /// Flag of the current instance whether it is canceled.
103    /// </summary>
104    protected bool myCanceled;
105    /// <summary>
106    /// Gets information whether the instance is currently canceled.
107    /// </summary>
108    public bool Canceled {
109      get { return myCanceled; }
110    }
111    /// <summary>
112    /// Gets information whether the instance has already terminated.
113    /// </summary>
114    public virtual bool Terminated {
115      get { return ExecutionStack.Count == 0; }
116    }
117
118    /// <summary>
119    /// Initializes a new instance of <see cref="EngineBase"/> with a new global scope.
120    /// </summary>
121    /// <remarks>Calls <see cref="Reset"/>.</remarks>
122    protected EngineBase() {
123      myOperatorGraph = new OperatorGraph();
124      myGlobalScope = new Scope("Global");
125      myPriority = ThreadPriority.Normal;
126      myExecutionStack = new Stack<IOperation>();
127      Reset();
128    }
129
130    /// <summary>
131    /// Clones the current instance (deep clone).
132    /// </summary>
133    /// <remarks>Deep clone through <see cref="Auxiliary.Clone"/> method of helper class
134    /// <see cref="Auxiliary"/>.</remarks>
135    /// <param name="clonedObjects">Dictionary of all already clone objects. (Needed to avoid cycles.)</param>
136    /// <returns>The cloned object as <see cref="EngineBase"/>.</returns>
137    public override object Clone(IDictionary<Guid, object> clonedObjects) {
138      EngineBase clone = (EngineBase)base.Clone(clonedObjects);
139      clone.myOperatorGraph = (IOperatorGraph)Auxiliary.Clone(OperatorGraph, clonedObjects);
140      clone.myGlobalScope = (IScope)Auxiliary.Clone(GlobalScope, clonedObjects);
141      clone.myExecutionTime = ExecutionTime;
142      IOperation[] operations = new IOperation[ExecutionStack.Count];
143      ExecutionStack.CopyTo(operations, 0);
144      for (int i = operations.Length - 1; i >= 0; i--)
145        clone.myExecutionStack.Push((IOperation)Auxiliary.Clone(operations[i], clonedObjects));
146      clone.myRunning = Running;
147      clone.myCanceled = Canceled;
148      return clone;
149     
150    }
151
152    /// <inheritdoc/>
153    /// <remarks>Calls <see cref="ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback, object)"/>
154    /// of class <see cref="ThreadPool"/>.</remarks>
155    public virtual void Execute() {
156      myRunning = true;
157      myCanceled = false;
158      ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null);
159    }
160    /// <inheritdoc/>
161    /// <remarks>Calls <see cref="ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback, object)"/>
162    /// of class <see cref="ThreadPool"/>.</remarks>
163    public virtual void ExecuteSteps(int steps) {
164      myRunning = true;
165      myCanceled = false;
166      ThreadPool.QueueUserWorkItem(new WaitCallback(Run), steps);
167    }
168    /// <inheritdoc/>
169    /// <remarks>Calls <see cref="ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback, object)"/>
170    /// of class <see cref="ThreadPool"/>.</remarks>
171    public void ExecuteStep() {
172      ExecuteSteps(1);
173    }
174    /// <inheritdoc/>
175    /// <remarks>Sets the protected flag <c>myCanceled</c> to <c>true</c>.</remarks>
176    public virtual void Abort() {
177      myCanceled = true;
178    }
179    /// <inheritdoc/>
180    /// <remarks>Sets <c>myCanceled</c> and <c>myRunning</c> to <c>false</c>. The global scope is cleared,
181    /// the execution time is reseted, the execution stack is cleared and a new <see cref="AtomicOperation"/>
182    /// with the initial operator is added. <br/>
183    /// Calls <see cref="OnInitialized"/>.</remarks>
184    public virtual void Reset() {
185      myCanceled = false;
186      myRunning = false;
187      GlobalScope.Clear();
188      ExecutionTime = new TimeSpan();
189      myExecutionStack.Clear();
190      if (OperatorGraph.InitialOperator != null)
191        myExecutionStack.Push(new AtomicOperation(OperatorGraph.InitialOperator, GlobalScope));
192      OnInitialized();
193    }
194
195    private void Run(object state) {
196      Thread.CurrentThread.Priority = Priority;
197      if (state == null) Run();
198      else RunSteps((int)state);
199      myRunning = false;
200      Thread.CurrentThread.Priority = ThreadPriority.Normal;
201      OnFinished();
202    }
203    private void Run() {
204      DateTime start = DateTime.Now;
205      DateTime end;
206      while ((!Canceled) && (!Terminated)) {
207        ProcessNextOperation();
208        end = DateTime.Now;
209        ExecutionTime += end - start;
210        start = end;
211      }
212      ExecutionTime += DateTime.Now - start;
213    }
214    private void RunSteps(int steps) {
215      DateTime start = DateTime.Now;
216      DateTime end;
217      int step = 0;
218      while ((!Canceled) && (!Terminated) && (step < steps)) {
219        ProcessNextOperation();
220        step++;
221        end = DateTime.Now;
222        ExecutionTime += end - start;
223        start = end;
224      }
225      ExecutionTime += DateTime.Now - start;
226    }
227
228    /// <summary>
229    /// Performs the next operation.
230    /// </summary>
231    protected abstract void ProcessNextOperation();
232
233    /// <summary>
234    /// Occurs when the current instance is initialized.
235    /// </summary>
236    public event EventHandler Initialized;
237    /// <summary>
238    /// Fires a new <c>Initialized</c> event.
239    /// </summary>
240    protected virtual void OnInitialized() {
241      if (Initialized != null)
242        Initialized(this, new EventArgs());
243    }
244    /// <summary>
245    /// Occurs when an operation is executed.
246    /// </summary>
247    public event EventHandler<EventArgs<IOperation>> OperationExecuted;
248    /// <summary>
249    /// Fires a new <c>OperationExecuted</c> event.
250    /// </summary>
251    /// <param name="operation">The operation that has been executed.</param>
252    protected virtual void OnOperationExecuted(IOperation operation) {
253      if (OperationExecuted != null)
254        OperationExecuted(this, new EventArgs<IOperation>(operation));
255    }
256    /// <summary>
257    /// Occurs when an exception occured during the execution.
258    /// </summary>
259    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
260    /// <summary>
261    /// Aborts the execution and fires a new <c>ExceptionOccurred</c> event.
262    /// </summary>
263    /// <param name="exception">The exception that was thrown.</param>
264    protected virtual void OnExceptionOccurred(Exception exception) {
265      Abort();
266      if (ExceptionOccurred != null)
267        ExceptionOccurred(this, new EventArgs<Exception>(exception));
268    }
269    /// <summary>
270    /// Occurs when the execution time changed.
271    /// </summary>
272    public event EventHandler ExecutionTimeChanged;
273    /// <summary>
274    /// Fires a new <c>ExecutionTimeChanged</c> event.
275    /// </summary>
276    protected virtual void OnExecutionTimeChanged() {
277      if (ExecutionTimeChanged != null)
278        ExecutionTimeChanged(this, new EventArgs());
279    }
280    /// <summary>
281    /// Occurs when the execution is finished.
282    /// </summary>
283    public event EventHandler Finished;
284    /// <summary>
285    /// Fires a new <c>Finished</c> event.
286    /// </summary>
287    protected virtual void OnFinished() {
288      if (Finished != null)
289        Finished(this, new EventArgs());
290    }
291
292    #region Persistence Methods
293    /// <summary>
294    /// Saves the current instance as <see cref="XmlNode"/> in the specified <paramref name="document"/>.
295    /// </summary>
296    /// <remarks>Calls <see cref="StorableBase.GetXmlNode"/> of base class <see cref="ItemBase"/>.<br/>
297    /// A quick overview how the single elements of the current instance are saved:
298    /// <list type="bullet">
299    /// <item>
300    /// <term>Operator graph: </term>
301    /// <description>Saved as a child node with the tag name <c>OperatorGraph</c>.</description>
302    /// </item>
303    /// <item>
304    /// <term>Global scope: </term>
305    /// <description>Saved as a child node with the tag name <c>GlobalScope</c>.</description>
306    /// </item>
307    /// <item>
308    /// <term>Execution stack: </term>
309    /// <description>A child node is created with the tag name <c>ExecutionStack</c>. Beyond this child node
310    /// all operations of the execution stack are saved as child nodes.</description>
311    /// </item>
312    /// <item>
313    /// <term>Execution time: </term>
314    /// <description>Saved as a child node with the tag name <c>ExecutionTime</c>, where the execution
315    /// time is saved as string in the node's inner text.</description>
316    /// </item>
317    /// <item>
318    /// <term>Priority: </term>
319    /// <description>Saved as a child node with the tag name <c>Priority</c>, where the thread priority
320    /// is saved as string in the node's inner text.</description>
321    /// </item>
322    /// </list></remarks>
323    /// <param name="name">The (tag)name of the <see cref="XmlNode"/>.</param>
324    /// <param name="document">The <see cref="XmlDocument"/> where to save the data.</param>
325    /// <param name="persistedObjects">The dictionary of all already persisted objects. (Needed to avoid cycles.)</param>
326    /// <returns>The saved <see cref="XmlNode"/>.</returns>
327    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid,IStorable> persistedObjects) {
328      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
329
330      node.AppendChild(PersistenceManager.Persist("OperatorGraph", OperatorGraph, document, persistedObjects));
331      node.AppendChild(PersistenceManager.Persist("GlobalScope", GlobalScope, document, persistedObjects));
332
333      XmlNode stackNode = document.CreateNode(XmlNodeType.Element, "ExecutionStack", null);
334      IOperation[] operations = new IOperation[ExecutionStack.Count];
335      ExecutionStack.CopyTo(operations, 0);
336      for (int i = 0; i < operations.Length; i++)
337        stackNode.AppendChild(PersistenceManager.Persist(operations[i], document, persistedObjects));
338      node.AppendChild(stackNode);
339
340      XmlNode timeNode = document.CreateNode(XmlNodeType.Element, "ExecutionTime", null);
341      timeNode.InnerText = ExecutionTime.ToString();
342      node.AppendChild(timeNode);
343      XmlNode priorityNode = document.CreateNode(XmlNodeType.Element, "Priority", null);
344      priorityNode.InnerText = Priority.ToString();
345      node.AppendChild(priorityNode);
346      return node;
347    }
348    /// <summary>
349    ///  Loads the persisted instance from the specified <paramref name="node"/>.
350    /// </summary>
351    /// <remarks>See <see cref="GetXmlNode"/> to get information on how the instance must be saved. <br/>
352    /// Calls <see cref="StorableBase.Populate"/> of base class <see cref="ItemBase"/>.</remarks>
353    /// <param name="node">The <see cref="XmlNode"/> where the engine is saved.</param>
354    /// <param name="restoredObjects">The dictionary of all already restored objects.
355    /// (Needed to avoid cycles.)</param>
356    public override void Populate(XmlNode node, IDictionary<Guid,IStorable> restoredObjects) {
357      base.Populate(node, restoredObjects);
358      myOperatorGraph = (IOperatorGraph)PersistenceManager.Restore(node.SelectSingleNode("OperatorGraph"), restoredObjects);
359      myGlobalScope = (IScope)PersistenceManager.Restore(node.SelectSingleNode("GlobalScope"), restoredObjects);
360
361      XmlNode stackNode = node.SelectSingleNode("ExecutionStack");
362      for (int i = stackNode.ChildNodes.Count - 1; i >= 0; i--)
363        myExecutionStack.Push((IOperation)PersistenceManager.Restore(stackNode.ChildNodes[i], restoredObjects));
364
365      XmlNode timeNode = node.SelectSingleNode("ExecutionTime");
366      myExecutionTime = TimeSpan.Parse(timeNode.InnerText);
367      XmlNode priorityNode = node.SelectSingleNode("Priority");
368      if (priorityNode != null)
369        myPriority = (ThreadPriority) Enum.Parse(typeof(ThreadPriority), priorityNode.InnerText);
370    }
371    #endregion
372  }
373}
Note: See TracBrowser for help on using the repository browser.