Files CCore/inc/PerTask.h CCore/src/PerTask.cpp
PerTask is an advanced tool to work with per-task objects. The class PerTask itself is not required to work directly with, but it is used indirectly once you deal with a particular per-task object.
class PerTask : NoCopy
{
....
public:
static PerTask * Get();
static PerTask * TryGet() noexcept;
static PerTask * Peak() noexcept;
template <class TOC>
typename TOC::ObjectType * getTaskObject();
template <class TOC>
typename TOC::ObjectType * tryGetTaskObject() noexcept;
template <class TOC>
void destroyTaskObject();
template <class TOC>
static void SetBuilder(typename TOC::BuilderType *builder);
template <class TOC>
static void ClearBuilder();
};
Each task may have an associated PerTask object. To retrieve the pointer to this object use the method PerTask::Get() (or PerTask::TryGet()). If there is no such object yet, it is created. An exception is thrown in case of error (null pointer is returned).
A PerTask object is destroyed, once the host task is finished. It is guaranteed for tasks, created with the Task class help, so it is always true for XCore platforms. For HCore platform you may, however, create a task not using the Task class. If such task is using PerTask feature, you must use the class DestroyPerTask to cleanup the correspondent PerTask object. The main task destroys its PerTask object after the function main() is finished. Sometime it is too late. You may use the class DestroyPerTask for the earlier termination.
class DestroyPerTask : NoCopy
{
public:
~DestroyPerTask();
};
DestroyPerTask destructor destroys PerTask object of the current task.
A PerTask object should not be used directly. It serves as a container for particular per-task objects. Each particular per-task object is described by its Task-Object-Control class. Such class must comply with the following pattern:
struct TaskObjectControl
{
static const Unid TypeUnid;
class ObjectType
{
public:
void destroy();
};
class BuilderType
{
public:
ObjectType * create();
};
};
It is a structure with two inner types: ObjectType and BuilderType. ObjectType is the type of the per-task object. BuilderType is the type of class which is used to build a per-task object. Its method create() is used to create an object. To destroy an object the method destroy() is used.
template <class TOC> typename TOC::ObjectType * GetTaskObject() { return PerTask::Get()->getTaskObject<TOC>(); } template <class TOC> typename TOC::ObjectType * TryGetTaskObject() noexcept { if( PerTask *obj=PerTask::TryGet() ) return obj->tryGetTaskObject<TOC>(); return 0; }
Two global functions can be used to get a particular per-task object: GetTaskObject<TOC>() and TryGetTaskObject<TOC>(). If the object is not created yet, it is constructed using the assigned builder object. An exception is thrown in case of error (null pointer is returned). But before you must assign an object builder. This is what the class TaskObjectBuild<TOC> is designed for.
template <class TOC>
class TaskObjectBuild : NoCopy
{
using BuilderType = typename TOC::BuilderType ;
BuilderType builder;
public:
template <class ... SS>
explicit TaskObjectBuild(SS && ... ss)
: builder( std::forward<SS>(ss)... )
{
PerTask::SetBuilder<TOC>(&builder);
}
~TaskObjectBuild()
{
PerTask::ClearBuilder<TOC>();
}
};
In the constructor of this class the builder object is created and made active. If some builder is already active an exception is thrown. In destructor the builder is deactivated.
To control the life-time of the per-task object the class PerTaskObjectScope is used.
template <class TOC>
class PerTaskObjectScope : NoCopy
{
void destroy()
{
if( PerTask *obj=PerTask::Peak() ) obj->destroyTaskObject<TOC>();
}
public:
explicit PerTaskObjectScope(bool clean=true)
{
if( clean ) destroy();
}
~PerTaskObjectScope()
{
destroy();
}
};
It destroys the per-task object in destructor. If the constructor argument is true (by default) it is also doing in the constructor.