|
Shinya Kitaoka |
810553 |
#pragma once
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifndef TTHREAD_H
|
|
Toshihiro Shimizu |
890ddd |
#define TTHREAD_H
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tsmartpointer.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include <qthread></qthread>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#undef DVAPI
|
|
Toshihiro Shimizu |
890ddd |
#undef DVVAR
|
|
Toshihiro Shimizu |
890ddd |
#ifdef TNZCORE_EXPORTS
|
|
Toshihiro Shimizu |
890ddd |
#define DVAPI DV_EXPORT_API
|
|
Toshihiro Shimizu |
890ddd |
#define DVVAR DV_EXPORT_VAR
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
#define DVAPI DV_IMPORT_API
|
|
Toshihiro Shimizu |
890ddd |
#define DVVAR DV_IMPORT_VAR
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace TThread {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! Initializes all TThread namespace components.
|
|
Toshihiro Shimizu |
890ddd |
void DVAPI init();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! Closes all TThread components as soon as possible in a safe manner.
|
|
Toshihiro Shimizu |
890ddd |
//! \sa Executor::shutdown() method
|
|
Toshihiro Shimizu |
890ddd |
void DVAPI shutdown();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Forward declarations
|
|
Shinya Kitaoka |
120a6e |
class ExecutorId; // Private
|
|
Toshihiro Shimizu |
890ddd |
class Runnable;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Campbell Barton |
107701 |
#if !(defined(MACOSX) || defined(LINUX))
|
|
Toshihiro Shimizu |
890ddd |
template class TSmartPointerT<runnable>;</runnable>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
typedef TSmartPointerT<runnable> RunnableP;</runnable>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Runnable class is the abstract model for user-defined tasks which can be
|
|
Toshihiro Shimizu |
890ddd |
scheduled for execution into separate application threads.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
A user must first implement the run() method to provide a task with the
|
|
Shinya Kitaoka |
120a6e |
very execution code. Worker threads created internally by the task manager
|
|
Shinya Kitaoka |
120a6e |
will
|
|
Toshihiro Shimizu |
890ddd |
take ownership of the task and make it run() at the most appropriate time,
|
|
Toshihiro Shimizu |
890ddd |
depending on the task load, insertion time and its scheduling priority.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Toshihiro Shimizu |
890ddd |
The scheduling priority of a task can be set by reimplementing the
|
|
Toshihiro Shimizu |
890ddd |
\b schedulingPriority() method. Tasks whose scheduling priority is higher are
|
|
Toshihiro Shimizu |
890ddd |
always started before compared to the others added by the same executor.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Toshihiro Shimizu |
890ddd |
The hosting thread's running priority may also be set reimplementing the
|
|
Toshihiro Shimizu |
890ddd |
runningPriority() method; see QThread class documentation in Qt manual.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Toshihiro Shimizu |
890ddd |
A task's load is an important property that should be reimplemented in all
|
|
Toshihiro Shimizu |
890ddd |
resource-consuming tasks. It enables the user to declare the approximate
|
|
Toshihiro Shimizu |
890ddd |
CPU load produced by a task, allowing the task manager to effectively
|
|
Toshihiro Shimizu |
890ddd |
calculate the most appropriate moment to run it.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\warning \n All built-in signals about the Runnable class are emitted in a
|
|
Shinya Kitaoka |
120a6e |
mutex-protected environment in order to make sure that signal emission is
|
|
Shinya Kitaoka |
120a6e |
consistent
|
|
Shinya Kitaoka |
120a6e |
with the task status - in other words, so that \a queued controller-emitted
|
|
Shinya Kitaoka |
120a6e |
canceled()
|
|
Toshihiro Shimizu |
890ddd |
and terminated() signals are not delivered \a before started() or \a after
|
|
Toshihiro Shimizu |
890ddd |
finished() and exception() worker-emitted signals.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
\warning Thus, setting up blocking connections or blocking direct slots is \b
|
|
Shinya Kitaoka |
120a6e |
not \b
|
|
Shinya Kitaoka |
120a6e |
supported and will typically result in deadlocks; furthermore, the same also
|
|
Shinya Kitaoka |
120a6e |
applies to
|
|
Shinya Kitaoka |
120a6e |
slot calls to the Executor API, which would have the aforementioned mutex to
|
|
Shinya Kitaoka |
120a6e |
be
|
|
Toshihiro Shimizu |
890ddd |
locked again.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
\warning In case the above blocking strategies are mandatory, the user should
|
|
Shinya Kitaoka |
120a6e |
add
|
|
Shinya Kitaoka |
120a6e |
custom signals to be emitted inside the mutex-free run() block, just before or
|
|
Shinya Kitaoka |
120a6e |
after
|
|
Toshihiro Shimizu |
890ddd |
the actual code to be executed, like this:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\code
|
|
Toshihiro Shimizu |
890ddd |
void MyTask::run()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
try
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
emit myStarted(this);
|
|
Toshihiro Shimizu |
890ddd |
theRunCode();
|
|
Toshihiro Shimizu |
890ddd |
emit myFinished(this);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
catch(...)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
emit myException(this);
|
|
Toshihiro Shimizu |
890ddd |
throw;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
\endcode
|
|
Toshihiro Shimizu |
890ddd |
\code
|
|
Toshihiro Shimizu |
890ddd |
..
|
|
Toshihiro Shimizu |
890ddd |
MyTask* myTask = new MyTask;
|
|
Shinya Kitaoka |
120a6e |
connect(myTask, SIGNAL(myStarted(TThread::RunnableP)), myTask,
|
|
Shinya Kitaoka |
120a6e |
SLOT(onStarted(TThread::RunnableP)),
|
|
Shinya Kitaoka |
120a6e |
Qt::BlockingQueuedConnection) //theRunCode() waits for onStarted() to
|
|
Shinya Kitaoka |
120a6e |
complete
|
|
Toshihiro Shimizu |
890ddd |
..
|
|
Toshihiro Shimizu |
890ddd |
\endcode
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\sa Executor class.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Shinya Kitaoka |
120a6e |
class DVAPI Runnable : public QObject, public TSmartObject {
|
|
Shinya Kitaoka |
120a6e |
Q_OBJECT
|
|
Shinya Kitaoka |
120a6e |
DECLARE_CLASS_CODE
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
ExecutorId *m_id;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int m_load;
|
|
Shinya Kitaoka |
120a6e |
int m_schedulingPriority;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
friend class Executor; // Needed to confront Executor's and Runnable's ids
|
|
Shinya Kitaoka |
120a6e |
friend class ExecutorImp; // The internal task manager needs full control
|
|
Shinya Kitaoka |
120a6e |
// over the task
|
|
Shinya Kitaoka |
38fd86 |
friend class Worker; // Workers force tasks to emit state signals
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
Runnable();
|
|
Shinya Kitaoka |
120a6e |
virtual ~Runnable();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
//! The central code of the task that is executed by a worker thread.
|
|
Shinya Kitaoka |
120a6e |
virtual void run() = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
virtual int taskLoad();
|
|
Shinya Kitaoka |
120a6e |
virtual int schedulingPriority();
|
|
Shinya Kitaoka |
120a6e |
virtual QThread::Priority runningPriority();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
Q_SIGNALS:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void started(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
void finished(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
void exception(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
void canceled(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
void terminated(TThread::RunnableP sender);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public Q_SLOTS:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
virtual void onStarted(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
virtual void onFinished(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
virtual void onException(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
virtual void onCanceled(TThread::RunnableP sender);
|
|
Shinya Kitaoka |
120a6e |
virtual void onTerminated(TThread::RunnableP sender);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
inline bool needsAccumulation();
|
|
Shinya Kitaoka |
120a6e |
inline bool customConditions();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Executor class provides an effective way for planning the execution of
|
|
Toshihiro Shimizu |
890ddd |
user-defined tasks that require separate working threads.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
When an application needs to perform a resource-consuming task, it is often
|
|
Shinya Kitaoka |
120a6e |
a good idea to dedicate a separate thread for it, especially in GUI
|
|
Shinya Kitaoka |
120a6e |
applications;
|
|
Toshihiro Shimizu |
890ddd |
however, doing so eventually raises the problem of managing such intensive
|
|
Shinya Kitaoka |
120a6e |
tasks in a way that constantly ensures the correct use of the machine
|
|
Shinya Kitaoka |
120a6e |
resources -
|
|
Toshihiro Shimizu |
890ddd |
so that in any given time the CPU usage is maximal, but not overloaded.
|
|
Toshihiro Shimizu |
890ddd |
Additional requests by the user may arise, including preferenced ordering
|
|
Toshihiro Shimizu |
890ddd |
among tasks, the necessity of salvaging some CPU resources or threads for
|
|
Toshihiro Shimizu |
890ddd |
incoming tasks, and so on.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Shinya Kitaoka |
120a6e |
The TThread namespace API contains two main classes, \b Runnable and \b
|
|
Shinya Kitaoka |
120a6e |
Executor,
|
|
Toshihiro Shimizu |
890ddd |
which provide a way for implementing consistent threading strategies.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Shinya Kitaoka |
120a6e |
In order to use the Executor class it is first necessary to install the thread
|
|
Shinya Kitaoka |
120a6e |
manager
|
|
Toshihiro Shimizu |
890ddd |
into application code by calling the static method init() appropriately.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Shinya Kitaoka |
120a6e |
Executors are then used to submit - or eventually remove - tasks for execution
|
|
Shinya Kitaoka |
120a6e |
into a
|
|
Shinya Kitaoka |
120a6e |
separate working thread, by means of the \b addTask(), \b removeTask() and \b
|
|
Shinya Kitaoka |
120a6e |
cancelAll() methods.
|
|
Toshihiro Shimizu |
890ddd |
Each Executor's visibility is always limited to the tasks that it submits -
|
|
Toshihiro Shimizu |
890ddd |
so calling removeTask() or cancelAll() only affects the tasks previously
|
|
Shinya Kitaoka |
120a6e |
added by that same Executor - which easily reflects the idea of an Executor
|
|
Shinya Kitaoka |
120a6e |
representing
|
|
Toshihiro Shimizu |
890ddd |
a group of tasks.
|
|
Toshihiro Shimizu |
890ddd |
\n \n
|
|
Shinya Kitaoka |
120a6e |
Basic control over the execution strategy for the group of tasks submitted by
|
|
Shinya Kitaoka |
120a6e |
an Executor
|
|
Shinya Kitaoka |
120a6e |
can be acquired using the setMaxActiveTasks() and setMaxActiveLoad() methods,
|
|
Shinya Kitaoka |
120a6e |
both granting
|
|
Toshihiro Shimizu |
890ddd |
the possibility to bound the execution of tasks to custom maximum conditions.
|
|
Shinya Kitaoka |
120a6e |
For example, use setMaxActiveTasks(1) to force the execution of 1 task only at
|
|
Shinya Kitaoka |
120a6e |
a time,
|
|
Toshihiro Shimizu |
890ddd |
or setMaxActiveLoad(100) to set a single CPU core available for the group.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\sa \b Runnable class documentation.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Shinya Kitaoka |
120a6e |
class DVAPI Executor {
|
|
Shinya Kitaoka |
120a6e |
ExecutorId *m_id;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
friend class ExecutorImp;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
Executor();
|
|
Shinya Kitaoka |
120a6e |
~Executor();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
static void init();
|
|
Shinya Kitaoka |
120a6e |
static void shutdown();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void addTask(RunnableP task);
|
|
Shinya Kitaoka |
120a6e |
void removeTask(RunnableP task);
|
|
Shinya Kitaoka |
120a6e |
void cancelAll();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void setMaxActiveTasks(int count);
|
|
Shinya Kitaoka |
120a6e |
void setMaxActiveLoad(int load);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int maxActiveTasks() const;
|
|
Shinya Kitaoka |
120a6e |
int maxActiveLoad() const;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void setDedicatedThreads(bool dedicated, bool persistent = true);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
// not implemented
|
|
Shinya Kitaoka |
120a6e |
Executor &operator=(const Executor &);
|
|
Shinya Kitaoka |
120a6e |
Executor(const Executor &);
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace TThread
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
#endif // TTHREAD_H
|