1 #pragma once
2 
3 #ifndef TTHREAD_H
4 #define TTHREAD_H
5 
6 #include "tsmartpointer.h"
7 
8 #include <QThread>
9 
10 #undef DVAPI
11 #undef DVVAR
12 #ifdef TNZCORE_EXPORTS
13 #define DVAPI DV_EXPORT_API
14 #define DVVAR DV_EXPORT_VAR
15 #else
16 #define DVAPI DV_IMPORT_API
17 #define DVVAR DV_IMPORT_VAR
18 #endif
19 
20 namespace TThread {
21 
22 //------------------------------------------------------------------------------
23 
24 //! Initializes all TThread namespace components.
25 void DVAPI init();
26 
27 //! Closes all TThread components as soon as possible in a safe manner.
28 //! \sa Executor::shutdown() method
29 void DVAPI shutdown();
30 
31 //------------------------------------------------------------------------------
32 
33 // Forward declarations
34 class ExecutorId;  // Private
35 class Runnable;
36 
37 }  // namespace TThread
38 #ifdef _WIN32
39 template class DVAPI TSmartPointerT<TThread::Runnable>;
40 #endif
41 namespace TThread {
42 
43 typedef TSmartPointerT<Runnable> RunnableP;
44 
45 //------------------------------------------------------------------------------
46 
47 /*!
48   Runnable class is the abstract model for user-defined tasks which can be
49   scheduled for execution into separate application threads.
50 
51   A user must first implement the run() method to provide a task with the
52   very execution code. Worker threads created internally by the task manager
53 will
54   take ownership of the task and make it run() at the most appropriate time,
55   depending on the task load, insertion time and its scheduling priority.
56 \n \n
57   The scheduling priority of a task can be set by reimplementing the
58   \b schedulingPriority() method. Tasks whose scheduling priority is higher are
59   always started before compared to the others added by the same executor.
60 \n \n
61   The hosting thread's running priority may also be set reimplementing the
62   runningPriority() method; see QThread class documentation in Qt manual.
63 \n \n
64   A task's load is an important property that should be reimplemented in all
65   resource-consuming tasks. It enables the user to declare the approximate
66   CPU load produced by a task, allowing the task manager to effectively
67   calculate the most appropriate moment to run it.
68 
69   \warning \n All built-in signals about the Runnable class are emitted in a
70   mutex-protected environment in order to make sure that signal emission is
71 consistent
72   with the task status - in other words, so that \a queued controller-emitted
73 canceled()
74   and terminated() signals are not delivered \a before started() or \a after
75   finished() and exception() worker-emitted signals.
76 
77   \warning Thus, setting up blocking connections or blocking direct slots is \b
78 not \b
79   supported and will typically result in deadlocks; furthermore, the same also
80 applies to
81   slot calls to the Executor API, which would have the aforementioned mutex to
82 be
83   locked again.
84 
85   \warning In case the above blocking strategies are mandatory, the user should
86 add
87   custom signals to be emitted inside the mutex-free run() block, just before or
88 after
89   the actual code to be executed, like this:
90 
91   \code
92   void MyTask::run()
93   {
94     try
95     {
96       emit myStarted(this);
97       theRunCode();
98       emit myFinished(this);
99     }
100     catch(...)
101     {
102       emit myException(this);
103       throw;
104     }
105   }
106   \endcode
107   \code
108   ..
109   MyTask* myTask = new MyTask;
110   connect(myTask, SIGNAL(myStarted(TThread::RunnableP)), myTask,
111 SLOT(onStarted(TThread::RunnableP)),
112     Qt::BlockingQueuedConnection)   //theRunCode() waits for onStarted() to
113 complete
114   ..
115   \endcode
116 
117   \sa Executor class.
118 */
119 class DVAPI Runnable : public QObject, public TSmartObject {
120   Q_OBJECT
121   DECLARE_CLASS_CODE
122 
123   ExecutorId *m_id;
124 
125   int m_load;
126   int m_schedulingPriority;
127 
128   friend class Executor;     // Needed to confront Executor's and Runnable's ids
129   friend class ExecutorImp;  // The internal task manager needs full control
130                              // over the task
131   friend class Worker;       // Workers force tasks to emit state signals
132 
133 public:
134   Runnable();
135   virtual ~Runnable();
136 
137   //! The central code of the task that is executed by a worker thread.
138   virtual void run() = 0;
139 
140   virtual int taskLoad();
141   virtual int schedulingPriority();
142   virtual QThread::Priority runningPriority();
143 
144 Q_SIGNALS:
145 
146   void started(TThread::RunnableP sender);
147   void finished(TThread::RunnableP sender);
148   void exception(TThread::RunnableP sender);
149   void canceled(TThread::RunnableP sender);
150   void terminated(TThread::RunnableP sender);
151 
152 public Q_SLOTS:
153 
154   virtual void onStarted(TThread::RunnableP sender);
155   virtual void onFinished(TThread::RunnableP sender);
156   virtual void onException(TThread::RunnableP sender);
157   virtual void onCanceled(TThread::RunnableP sender);
158   virtual void onTerminated(TThread::RunnableP sender);
159 
160 private:
161   inline bool needsAccumulation();
162   inline bool customConditions();
163 };
164 
165 //------------------------------------------------------------------------------
166 
167 /*!
168   Executor class provides an effective way for planning the execution of
169   user-defined tasks that require separate working threads.
170 
171   When an application needs to perform a resource-consuming task, it is often
172   a good idea to dedicate a separate thread for it, especially in GUI
173 applications;
174   however, doing so eventually raises the problem of managing such intensive
175   tasks in a way that constantly ensures the correct use of the machine
176 resources -
177   so that in any given time the CPU usage is maximal, but not overloaded.
178   Additional requests by the user may arise, including preferenced ordering
179   among tasks, the necessity of salvaging some CPU resources or threads for
180   incoming tasks, and so on.
181 \n \n
182   The TThread namespace API contains two main classes, \b Runnable and \b
183 Executor,
184   which provide a way for implementing consistent threading strategies.
185 \n \n
186   In order to use the Executor class it is first necessary to install the thread
187 manager
188   into application code by calling the static method init() appropriately.
189 \n \n
190   Executors are then used to submit - or eventually remove - tasks for execution
191 into a
192   separate working thread, by means of the \b addTask(), \b removeTask() and \b
193 cancelAll() methods.
194   Each Executor's visibility is always limited to the tasks that it submits -
195   so calling removeTask() or cancelAll() only affects the tasks previously
196   added by that same Executor - which easily reflects the idea of an Executor
197 representing
198   a group of tasks.
199 \n \n
200   Basic control over the execution strategy for the group of tasks submitted by
201 an Executor
202   can be acquired using the setMaxActiveTasks() and setMaxActiveLoad() methods,
203 both granting
204   the possibility to bound the execution of tasks to custom maximum conditions.
205   For example, use setMaxActiveTasks(1) to force the execution of 1 task only at
206 a time,
207   or setMaxActiveLoad(100) to set a single CPU core available for the group.
208 
209   \sa \b Runnable class documentation.
210 */
211 class DVAPI Executor {
212   ExecutorId *m_id;
213 
214   friend class ExecutorImp;
215 
216 public:
217   Executor();
218   ~Executor();
219 
220   static void init();
221   static void shutdown();
222 
223   void addTask(RunnableP task);
224   void removeTask(RunnableP task);
225   void cancelAll();
226 
227   void setMaxActiveTasks(int count);
228   void setMaxActiveLoad(int load);
229 
230   int maxActiveTasks() const;
231   int maxActiveLoad() const;
232 
233   void setDedicatedThreads(bool dedicated, bool persistent = true);
234 
235 private:
236   // not implemented
237   Executor &operator=(const Executor &);
238   Executor(const Executor &);
239 };
240 
241 }  // namespace TThread
242 
243 #endif  // TTHREAD_H
244