MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
workunit.h
Go to the documentation of this file.
1 // The DAGFrameScheduler is a Multi-Threaded lock free and wait free scheduling library.
2 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
3 /* This file is part of The DAGFrameScheduler.
4 
5  The DAGFrameScheduler is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  The DAGFrameScheduler is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with The DAGFrameScheduler. If not, see <http://www.gnu.org/licenses/>.
17 */
18 /* The original authors have included a copy of the license specified above in the
19  'doc' folder. See 'gpl.txt'
20 */
21 /* We welcome the use of the DAGFrameScheduler to anyone, including companies who wish to
22  Build professional software and charge for their product.
23 
24  However there are some practical restrictions, so if your project involves
25  any of the following you should contact us and we will try to work something
26  out:
27  - DRM or Copy Protection of any kind(except Copyrights)
28  - Software Patents You Do Not Wish to Freely License
29  - Any Kind of Linking to Non-GPL licensed Works
30  - Are Currently In Violation of Another Copyright Holder's GPL License
31  - If You want to change our code and not add a few hundred MB of stuff to
32  your distribution
33 
34  These and other limitations could cause serious legal problems if you ignore
35  them, so it is best to simply contact us or the Free Software Foundation, if
36  you have any questions.
37 
38  Joseph Toppi - toppij@gmail.com
39  John Blackwood - makoenergy02@gmail.com
40 */
41 #ifndef _workunit_h
42 #define _workunit_h
43 
44 #include "datatypes.h"
45 
46 #if !defined(SWIG) || defined(SWIG_THREADING) // Do not read when in swig and not in the threading module
47 #include "framescheduler.h"
48 #include "mutex.h"
49 #include "rollingaverage.h"
50 #include "threadingenumerations.h"
51 #include "thread.h"
52 #include "workunitkey.h"
53 #endif
54 
55 /// @file
56 /// @brief This file has the definition of the workunit.
57 
58 namespace Mezzanine
59 {
60  namespace Threading
61  {
62  /// @brief Interface of a WorkUnit. This represents on piece of work through time.
63  /// @details This has no real substance, use the DefaultWorkUnit class is you
64  /// want to inherit from something ready for easy integration. Implement this
65  /// if you want to make heavy changes to the algorithm or maximize performance.
67  {
68  public:
69  /////////////////////////////////////////////////////////////////////////////////////////////
70  // Work with the dependents as in what WorkUnits must not start until this finishes.
71 
72  /// @brief This returns the count workunits that depend on this work unit.
73  /// @param SchedulerToCount The @ref FrameScheduler has a cache of this data, it is impossible to calculate without the complete list of WorkUnits on it either.
74  /// @details Because Dependents are not tracked this iterates over entry in the FrameScheduler it is passed.
75  /// @return A Whole is returned containing the count.
76  virtual Whole GetDependentCount(FrameScheduler &SchedulerToCount) = 0;
77 
78 
79  /////////////////////////////////////////////////////////////////////////////////////////////
80  // Work with the dependencies as in what must finish before we can run this work unit.
81 
82  /// @brief This is used to iterate of all the dependencies.
83  /// @param Index The 0 based index of the dependency you are trying to retrieve. No ordering is guaranteed, just that counting from 0 to @ref GetImmediateDependencyCount() with access each iWorkUnit once.
84  /// @return A pointer to an iWorkUnit.
85  virtual iWorkUnit* GetDependency(Whole Index) const = 0;
86 
87  /// @brief Get the amount of dependencies that directly count on this for access purposes.
88  /// @return The amount of accessable WorkUnit from this WorkUnits dependency list.
89  virtual Whole GetImmediateDependencyCount() const = 0;
90 
91  /// @brief How many other WorkUnits does this one depend on?
92  /// @details This is what the @ref FrameScheduler uses to calculate the
93  /// sorting order of WorkUnits. In the default implmentation it counts
94  /// some units twice if they depend on this WorkUnit through Multiple
95  /// dependency chains.
96  /// @return A Whole containing the answer.
97  virtual Whole GetDependencyCount() const = 0;
98 
99  /// @brief Force this WorkUnit to Start after another has completed.
100  /// @param NewDependency The WorkUnit that must start after this one has completed.
101  /// @warning Changing this outside the schedule, once the scheduler has started can cause undefined behavior.
102  virtual void AddDependency(iWorkUnit* NewDependency) = 0;
103 
104  /// @brief Remove a dependency.
105  /// @param RemoveDependency A pointer to the WorkUnit to remove as a dependency.
106  virtual void RemoveDependency(iWorkUnit* RemoveDependency) = 0;
107 
108  /// @brief Drop any information about what work units this one depends on.
109  virtual void ClearDependencies() = 0;
110 
111  /// @brief Check if this WorkUnit could concievably run right now.
112  /// @return This returns true if all of this WorkUnits dependencies have completed execution and false otherwise.
113  virtual bool IsEveryDependencyComplete() = 0;
114 
115 
116  /////////////////////////////////////////////////////////////////////////////////////////////
117  // Work with the ownership and RunningState
118 
119  /// @brief Attempts to atomically start the work unit in the current thread.
120  /// @return Returns RunningState::Starting if this thread was able to gain ownership and start the workunit, returns RunningState::NotStarted otherwise.
121  virtual RunningState TakeOwnerShip() = 0;
122 
123  /// @brief Retrieves the current RunningState of the thread.
124  /// @return A RunningState that indicates if the thread is running, started, etc... This information can be changed at any time and should be considered stale immediately after retrieval.
125  virtual RunningState GetRunningState() const = 0;
126 
127  /// @brief This resets the running state and takes any further action required to use the WorkUnit again.
128  virtual void PrepareForNextFrame() = 0;
129 
130 
131  /////////////////////////////////////////////////////////////////////////////////////////////
132  // Work with the preformance log
133 
134  /// @brief Get the internal rolling average for querying.
135  /// @return A whole that represents this WorkUnits Performance.
136  virtual Whole GetPerformance() const = 0;
137 
138 
139  /////////////////////////////////////////////////////////////////////////////////////////////
140  // Deciding when to and doing the work
141 
142  /// @brief This tracks work unit metadata, then calls DoWork.
143  /// @param CurrentThreadStorage The @ref ThreadSpecificStorage that this WorkUnit will operate with when executing.
144  virtual void operator() (DefaultThreadSpecificStorage::Type& CurrentThreadStorage) = 0;
145 
146  /// @brief Get the sorting metadata.
147  /// @param SchedulerToCount This uses the metadata on the @ref FrameScheduler to generate the Dependency listing required.
148  /// @return A WorkUnitKey suitable for sorting this workunit.
149  virtual WorkUnitKey GetSortingKey(FrameScheduler &SchedulerToCount) = 0;
150 
151  /// @brief WorkUnits Must implement these to do the work.
152  virtual void DoWork(DefaultThreadSpecificStorage::Type& CurrentThreadStorage) = 0;
153 
154  /// @brief Virtual destructor.
155  virtual ~iWorkUnit(){}
156  };//iWorkUnit
157 
158 
159  /// @brief Default implementation of WorkUnit. This represents on piece of work through time.
161  {
162  /////////////////////////////////////////////////////////////////////////////////////////////
163  // Data Members
164  protected:
165  /// @brief A collection of of workunits that must be complete before this one can start.
166  std::vector<iWorkUnit*> Dependencies;
167 
168  /// @brief A rolling average of execution times.
170 
171  /// @brief This controls do work with this after it has.
173 
174  /////////////////////////////////////////////////////////////////////////////////////////////
175  // The Simple Stuff
176  private:
177  /// @brief Remove Copy constructor, Copying a work unit does not make sense, it breaks scheduling, made private.
179 
180  /// @brief Assignment operator, Assignment on a WorkUnit Does Not make sense, it breaks scheduling, made private.
181  DefaultWorkUnit& operator=(DefaultWorkUnit& Unused);
182 
183  public:
184 #ifndef SWIG
185  /// @brief Simple constructor.
186  DefaultWorkUnit();
187 #endif
188  /// @brief Virtual destructor, doesn't actually do much.
189  virtual ~DefaultWorkUnit();
190 
191  /////////////////////////////////////////////////////////////////////////////////////////////
192  // Work with the dependents as in what must not start until this finishes.
193  public:
194  virtual Whole GetDependentCount(FrameScheduler &SchedulerToCount);
195 
196  /////////////////////////////////////////////////////////////////////////////////////////////
197  // Work with the dependents as in what WorkUnits must not start until this finishes.
198  public:
199  virtual iWorkUnit* GetDependency(Whole Index) const;
200 
201  virtual Whole GetImmediateDependencyCount() const;
202 
203  virtual Whole GetDependencyCount() const;
204 
205  public:
206  virtual void AddDependency(iWorkUnit* NewDependency);
207 
208  virtual void RemoveDependency(iWorkUnit* RemoveDependency);
209 
210  virtual void ClearDependencies();
211 
212  virtual bool IsEveryDependencyComplete();
213 
214  /////////////////////////////////////////////////////////////////////////////////////////////
215  // Work with the ownership and RunningState
216  public:
217  virtual RunningState TakeOwnerShip();
218 
219  virtual RunningState GetRunningState() const;
220 
221  virtual void PrepareForNextFrame();
222 
223  /////////////////////////////////////////////////////////////////////////////////////////////
224  // Work with the performance log
225  public:
226  virtual Whole GetPerformance() const;
227 
228  /// @brief Get the internal rolling average for querying.
229  /// @return A const reference to the internal Rolling Average.
230  virtual RollingAverage<Whole>& GetPerformanceLog();
231 
232  /////////////////////////////////////////////////////////////////////////////////////////////
233  // Deciding when to and doing the work
234  public:
235  /// @brief This does everything required to track metadata and log work
236  /// @param CurrentThreadStorage The FrameScheduler passes this in
237  /// @details This wraps the log output in a WorkUnit element with a unique ID
238  /// as and an attribute. This causes all the log output to be valid xml as long
239  /// no '<' or '>' are emitted.
240  /// @n @n
241  ///
242  virtual void operator() (DefaultThreadSpecificStorage::Type& CurrentThreadStorage);
243 
244  virtual WorkUnitKey GetSortingKey(FrameScheduler &SchedulerToCount);
245 
246  };//DefaultWorkUnit
247  }//Threading
248 }//Mezzanine
249 
250 #endif