#region License Information /* HeuristicLab * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Threading; namespace HeuristicLab.Core { /// /// Base class to represent an engine, which is an interpreter, holding the code, the data and /// the actual state, which is the runtime stack and a pointer onto the next operation. It represents /// one execution and can handle parallel executions. /// public abstract class EngineBase : ItemBase, IEngine { /// /// Field of the current instance that represent the operator graph. /// protected IOperatorGraph myOperatorGraph; /// /// Gets the current operator graph. /// public IOperatorGraph OperatorGraph { get { return myOperatorGraph; } } /// /// Field of the current instance that represent the global scope. /// protected IScope myGlobalScope; /// /// Gets the current global scope. /// public IScope GlobalScope { get { return myGlobalScope; } } private TimeSpan myExecutionTime; /// /// Gets or sets the execution time. /// /// Calls in the setter. public TimeSpan ExecutionTime { get { return myExecutionTime; } protected set { myExecutionTime = value; OnExecutionTimeChanged(); } } private ThreadPriority myPriority; /// /// Gets or sets the priority of the worker thread. /// public ThreadPriority Priority { get { return myPriority; } set { myPriority = value; } } /// /// Field of the current instance that represent the execution stack. /// protected Stack myExecutionStack; /// /// Gets the current execution stack. /// public Stack ExecutionStack { get { return myExecutionStack; } } /// /// Flag of the current instance whether it is currently running. /// protected bool myRunning; /// /// Gets information whether the instance is currently running. /// public bool Running { get { return myRunning; } } /// /// Flag of the current instance whether it is canceled. /// protected bool myCanceled; /// /// Gets information whether the instance is currently canceled. /// public bool Canceled { get { return myCanceled; } } /// /// Gets information whether the instance has already terminated. /// public virtual bool Terminated { get { return ExecutionStack.Count == 0; } } /// /// Initializes a new instance of with a new global scope. /// /// Calls . protected EngineBase() { myOperatorGraph = new OperatorGraph(); myGlobalScope = new Scope("Global"); myPriority = ThreadPriority.Normal; myExecutionStack = new Stack(); Reset(); } /// /// Clones the current instance (deep clone). /// /// Deep clone through method of helper class /// . /// Dictionary of all already clone objects. (Needed to avoid cycles.) /// The cloned object as . public override object Clone(IDictionary clonedObjects) { EngineBase clone = (EngineBase)base.Clone(clonedObjects); clone.myOperatorGraph = (IOperatorGraph)Auxiliary.Clone(OperatorGraph, clonedObjects); clone.myGlobalScope = (IScope)Auxiliary.Clone(GlobalScope, clonedObjects); clone.myExecutionTime = ExecutionTime; IOperation[] operations = new IOperation[ExecutionStack.Count]; ExecutionStack.CopyTo(operations, 0); for (int i = operations.Length - 1; i >= 0; i--) clone.myExecutionStack.Push((IOperation)Auxiliary.Clone(operations[i], clonedObjects)); clone.myRunning = Running; clone.myCanceled = Canceled; return clone; } /// /// Calls /// of class . public virtual void Execute() { myRunning = true; myCanceled = false; ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null); } /// /// Calls /// of class . public virtual void ExecuteSteps(int steps) { myRunning = true; myCanceled = false; ThreadPool.QueueUserWorkItem(new WaitCallback(Run), steps); } /// /// Calls /// of class . public void ExecuteStep() { ExecuteSteps(1); } /// /// Sets the protected flag myCanceled to true. public virtual void Abort() { myCanceled = true; } /// /// Sets myCanceled and myRunning to false. The global scope is cleared, /// the execution time is reseted, the execution stack is cleared and a new /// with the initial operator is added.
/// Calls .
public virtual void Reset() { myCanceled = false; myRunning = false; GlobalScope.Clear(); ExecutionTime = new TimeSpan(); myExecutionStack.Clear(); if (OperatorGraph.InitialOperator != null) myExecutionStack.Push(new AtomicOperation(OperatorGraph.InitialOperator, GlobalScope)); OnInitialized(); } private void Run(object state) { Thread.CurrentThread.Priority = Priority; if (state == null) Run(); else RunSteps((int)state); myRunning = false; Thread.CurrentThread.Priority = ThreadPriority.Normal; OnFinished(); } private void Run() { DateTime start = DateTime.Now; DateTime end; while ((!Canceled) && (!Terminated)) { ProcessNextOperation(); end = DateTime.Now; ExecutionTime += end - start; start = end; } ExecutionTime += DateTime.Now - start; } private void RunSteps(int steps) { DateTime start = DateTime.Now; DateTime end; int step = 0; while ((!Canceled) && (!Terminated) && (step < steps)) { ProcessNextOperation(); step++; end = DateTime.Now; ExecutionTime += end - start; start = end; } ExecutionTime += DateTime.Now - start; } /// /// Performs the next operation. /// protected abstract void ProcessNextOperation(); /// /// Occurs when the current instance is initialized. /// public event EventHandler Initialized; /// /// Fires a new Initialized event. /// protected virtual void OnInitialized() { if (Initialized != null) Initialized(this, new EventArgs()); } /// /// Occurs when an operation is executed. /// public event EventHandler OperationExecuted; /// /// Fires a new OperationExecuted event. /// /// The operation that has been executed. protected virtual void OnOperationExecuted(IOperation operation) { if (OperationExecuted != null) OperationExecuted(this, new OperationEventArgs(operation)); } /// /// Occurs when an exception occured during the execution. /// public event EventHandler ExceptionOccurred; /// /// Aborts the execution and fires a new ExceptionOccurred event. /// /// The exception that was thrown. protected virtual void OnExceptionOccurred(Exception exception) { Abort(); if (ExceptionOccurred != null) ExceptionOccurred(this, new ExceptionEventArgs(exception)); } /// /// Occurs when the execution time changed. /// public event EventHandler ExecutionTimeChanged; /// /// Fires a new ExecutionTimeChanged event. /// protected virtual void OnExecutionTimeChanged() { if (ExecutionTimeChanged != null) ExecutionTimeChanged(this, new EventArgs()); } /// /// Occurs when the execution is finished. /// public event EventHandler Finished; /// /// Fires a new Finished event. /// protected virtual void OnFinished() { if (Finished != null) Finished(this, new EventArgs()); } #region Persistence Methods /// /// Saves the current instance as in the specified . /// /// Calls of base class .
/// A quick overview how the single elements of the current instance are saved: /// /// /// Operator graph: /// Saved as a child node with the tag name OperatorGraph. /// /// /// Global scope: /// Saved as a child node with the tag name GlobalScope. /// /// /// Execution stack: /// A child node is created with the tag name ExecutionStack. Beyond this child node /// all operations of the execution stack are saved as child nodes. /// /// /// Execution time: /// Saved as a child node with the tag name ExecutionTime, where the execution /// time is saved as string in the node's inner text. /// /// /// Priority: /// Saved as a child node with the tag name Priority, where the thread priority /// is saved as string in the node's inner text. /// ///
/// The (tag)name of the . /// The where to save the data. /// The dictionary of all already persisted objects. (Needed to avoid cycles.) /// The saved . public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) { XmlNode node = base.GetXmlNode(name, document, persistedObjects); node.AppendChild(PersistenceManager.Persist("OperatorGraph", OperatorGraph, document, persistedObjects)); node.AppendChild(PersistenceManager.Persist("GlobalScope", GlobalScope, document, persistedObjects)); XmlNode stackNode = document.CreateNode(XmlNodeType.Element, "ExecutionStack", null); IOperation[] operations = new IOperation[ExecutionStack.Count]; ExecutionStack.CopyTo(operations, 0); for (int i = 0; i < operations.Length; i++) stackNode.AppendChild(PersistenceManager.Persist(operations[i], document, persistedObjects)); node.AppendChild(stackNode); XmlNode timeNode = document.CreateNode(XmlNodeType.Element, "ExecutionTime", null); timeNode.InnerText = ExecutionTime.ToString(); node.AppendChild(timeNode); XmlNode priorityNode = document.CreateNode(XmlNodeType.Element, "Priority", null); priorityNode.InnerText = Priority.ToString(); node.AppendChild(priorityNode); return node; } /// /// Loads the persisted instance from the specified . /// /// See to get information on how the instance must be saved.
/// Calls of base class .
/// The where the engine is saved. /// The dictionary of all already restored objects. /// (Needed to avoid cycles.) public override void Populate(XmlNode node, IDictionary restoredObjects) { base.Populate(node, restoredObjects); myOperatorGraph = (IOperatorGraph)PersistenceManager.Restore(node.SelectSingleNode("OperatorGraph"), restoredObjects); myGlobalScope = (IScope)PersistenceManager.Restore(node.SelectSingleNode("GlobalScope"), restoredObjects); XmlNode stackNode = node.SelectSingleNode("ExecutionStack"); for (int i = stackNode.ChildNodes.Count - 1; i >= 0; i--) myExecutionStack.Push((IOperation)PersistenceManager.Restore(stackNode.ChildNodes[i], restoredObjects)); XmlNode timeNode = node.SelectSingleNode("ExecutionTime"); myExecutionTime = TimeSpan.Parse(timeNode.InnerText); XmlNode priorityNode = node.SelectSingleNode("Priority"); if (priorityNode != null) myPriority = (ThreadPriority) Enum.Parse(typeof(ThreadPriority), priorityNode.InnerText); } #endregion } }