![]() |
Plasma Engine
2.0
|
This system allows to automatically distribute tasks onto a number of worker threads. More...
#include <TaskSystem.h>
Classes | |
struct | TaskData |
Static Public Member Functions | |
Utilities | |
static void | WriteStateSnapshotToDGML (plDGMLGraph &ref_graph) |
Writes the internal state of the plTaskSystem as a DGML graph. | |
static void | WriteStateSnapshotToFile (const char *szPath=nullptr) |
Convenience function to write the task graph snapshot to a file. If no path is given, the file is written to ":appdata/TaskGraphs/__date__.dgml". | |
Thread Management | |
class | plTaskWorkerThread |
static void | SetWorkerThreadCount (plInt32 iShortTasks=-1, plInt32 iLongTasks=-1) |
Sets the number of threads to use for the different task categories. | |
static plUInt32 | GetWorkerThreadCount (plWorkerThreadType::Enum type) |
Returns the maximum number of threads that should work on the given type of task at the same time. | |
static plUInt32 | GetNumAllocatedWorkerThreads (plWorkerThreadType::Enum type) |
Returns the number of threads that have been allocated to potentially work on the given type of task. | |
static plWorkerThreadType::Enum | GetCurrentThreadWorkerType () |
Returns the (thread local) type of tasks that would be executed on this thread. | |
static double | GetThreadUtilization (plWorkerThreadType::Enum type, plUInt32 uiThreadIndex, plUInt32 *pNumTasksExecuted=nullptr) |
Returns the utilization (0.0 to 1.0) of the given thread. Note: This will only be valid, if FinishFrameTasks() is called once per frame. | |
static void | WakeUpThreads (plWorkerThreadType::Enum type, plUInt32 uiNumThreads) |
[internal] Wakes up or allocates up to uiNumThreads, unless enough threads are currently active and not blocked | |
Misc | |
static void | SetTargetFrameTime (plTime targetFrameTime=plTime::MakeFromSeconds(1.0/40.0)) |
Sets the target frame time that is supposed to not be exceeded. | |
Managing Tasks | |
static plTaskGroupID | StartSingleTask (const plSharedPtr< plTask > &pTask, plTaskPriority::Enum priority, plOnTaskGroupFinishedCallback callback=plOnTaskGroupFinishedCallback()) |
A helper function to insert a single task into the system and start it right away. Returns ID of the Group into which the task has been put. | |
static plTaskGroupID | StartSingleTask (const plSharedPtr< plTask > &pTask, plTaskPriority::Enum priority, plTaskGroupID dependency, plOnTaskGroupFinishedCallback callback=plOnTaskGroupFinishedCallback()) |
A helper function to insert a single task into the system and start it right away. Returns ID of the Group into which the task has been put. This overload allows to additionally specify a single dependency. | |
static void | FinishFrameTasks () |
Call this function once at the end of a frame. It will ensure that all tasks for 'this frame' get finished properly. | |
static plResult | CancelTask (const plSharedPtr< plTask > &pTask, plOnTaskRunning::Enum onTaskRunning=plOnTaskRunning::WaitTillFinished) |
This function will try to remove the given task from the work queue, to prevent it from being executed. | |
Managing Task Groups | |
static plTaskGroupID | CreateTaskGroup (plTaskPriority::Enum priority, plOnTaskGroupFinishedCallback callback=plOnTaskGroupFinishedCallback()) |
Creates a new task group for one-time use. Groups need to be recreated every time a task is supposed to be inserted into the system. | |
static void | AddTaskToGroup (plTaskGroupID group, const plSharedPtr< plTask > &pTask) |
Adds a task to the given task group. The group must not yet have been started. | |
static void | AddTaskGroupDependency (plTaskGroupID group, plTaskGroupID dependsOn) |
Adds a dependency on another group to Group. This means Group will not be execute before DependsOn has finished. | |
static void | AddTaskGroupDependencyBatch (plArrayPtr< const plTaskGroupDependency > batch) |
Same as AddTaskGroupDependency() but batches multiple dependency additions. | |
static void | StartTaskGroup (plTaskGroupID group) |
Starts the task group. After this no further modifications on the group (new tasks or dependencies) are allowed. | |
static void | StartTaskGroupBatch (plArrayPtr< const plTaskGroupID > batch) |
Same as StartTaskGroup() but batches multiple actions. | |
static bool | IsTaskGroupFinished (plTaskGroupID group) |
Returns whether the given Group id refers to a task group that has been finished already. | |
static plResult | CancelGroup (plTaskGroupID group, plOnTaskRunning::Enum onTaskRunning=plOnTaskRunning::WaitTillFinished) |
Cancels all the tasks in the given group. | |
static void | WaitForGroup (plTaskGroupID group) |
Blocks until all tasks in the given group have finished. | |
static void | WaitForCondition (plDelegate< bool()> condition) |
Blocks the current thread until the given delegate returns true. | |
Parallel For | |
static void | ParallelForIndexed (plUInt32 uiStartIndex, plUInt32 uiNumItems, plParallelForIndexedFunction32 taskCallback, const char *szTaskName=nullptr, plTaskNesting taskNesting=plTaskNesting::Never, const plParallelForParams ¶ms=plParallelForParams()) |
A helper function to process task items in a parallel fashion by having per-worker index ranges generated. | |
static void | ParallelForIndexed (plUInt64 uiStartIndex, plUInt64 uiNumItems, plParallelForIndexedFunction64 taskCallback, const char *szTaskName=nullptr, plTaskNesting taskNesting=plTaskNesting::Never, const plParallelForParams ¶ms=plParallelForParams()) |
A helper function to process task items in a parallel fashion by having per-worker index ranges generated. | |
template<typename ElemType , typename Callback > | |
static void | ParallelFor (plArrayPtr< ElemType > taskItems, Callback taskCallback, const char *szTaskName=nullptr, const plParallelForParams ¶ms=plParallelForParams()) |
template<typename ElemType , typename Callback > | |
static void | ParallelForSingle (plArrayPtr< ElemType > taskItems, Callback taskCallback, const char *szTaskName=nullptr, const plParallelForParams ¶ms=plParallelForParams()) |
template<typename ElemType , typename Callback > | |
static void | ParallelForSingleIndex (plArrayPtr< ElemType > taskItems, Callback taskCallback, const char *szTaskName=nullptr, const plParallelForParams ¶ms=plParallelForParams()) |
This system allows to automatically distribute tasks onto a number of worker threads.
By deriving from plTask you can create your own task types. These can be executed through this task system. You can run a single task using the 'StartSingleTask' function. For more complex setups, it is possible to create groups of tasks, which can have interdependencies. This should be used to group all tasks that belong to one system and need to be done before another system runs. For example you could group all tasks to update particle systems, and then have another group for all tasks to update sound, which depends on the first group, such that sound is only updated after all particle systems are done with.
Although it is possible to wait for tasks or to cancel them, it is generally advised to try to minimize their use. Tasks that might need to be canceled regularly (e.g. path searches) should be implemented in a way that they are aware of being canceled and will stop their work prematurely, instead of running through to the end.
Note that it is crucial to call 'FinishFrameTasks' once per frame, otherwise tasks that need to be executed on the main thread are never executed.
|
static |
Adds a dependency on another group to Group. This means Group will not be execute before DependsOn has finished.
|
static |
Cancels all the tasks in the given group.
PL_SUCCESS is returned, if all tasks were already finished or could be removed without waiting for any of them. PL_FAILURE is returned, if at least one task was being processed by another thread and could not be removed without waiting. If bWaitForIt is false, the function cancels all tasks, but returns without blocking, even if not all tasks have been finished. If bWaitForIt is true, the function returns only after it is guaranteed that all tasks are properly terminated.
|
static |
This function will try to remove the given task from the work queue, to prevent it from being executed.
The function will return PL_SUCCESS, if the task could be removed and thus its execution could be prevented. It will also return PL_SUCCESS, if the task was already finished and nothing needed to be done. Tasks that are removed without execution will still be marked as 'finished' and dependent tasks will be scheduled.
PL_FAILURE is returned, if the task had already been started and thus could not be prevented from running.
In case of failure, bWaitForIt determines whether 'WaitForTask' is called (with all its consequences), or whether the function will return immediately.
The cancel flag is set on the task, such that tasks that support canceling might terminate earlier. However, there is no guarantee how long it takes for already running tasks to actually finish. Therefore when bWaitForIt is true, this function might block for a very long time. It is advised to implement tasks that need to be canceled regularly (e.g. path searches for units that might die) in a way that allows for quick canceling.
|
static |
Creates a new task group for one-time use. Groups need to be recreated every time a task is supposed to be inserted into the system.
All tasks that are added to this group will be run with the same given Priority. Once all tasks in the group are finished and thus the group is finished, an optional Callback can be executed.
|
static |
Call this function once at the end of a frame. It will ensure that all tasks for 'this frame' get finished properly.
Calling this function is crucial for several reasons. It is the central function to execute 'main thread' tasks. Otherwise these tasks might never get executed. It also changes the priority of all 'next frame' tasks to 'this frame', so that those tasks are guaranteed to get finished when 'FinishFrameTasks' is called the next time.
Finally this function executes tasks with the priority 'SomeFrameMainThread' as long as the target frame time is not exceeded. You can configure this with SetTargetFrameTime(), which defines how long (in milliseconds) the frame is allowed to be. As long as that time is not exceeded, additional 'SomeFrameMainThread' tasks will be executed. If the frame time spikes for a few frames, no such tasks will be executed, to prevent making it worse. However, if the frame time stays high over a longer period, 'FinishFrameTasks' will execute 'SomeFrameMainThread' tasks every once in a while, to guarantee some progress.
|
static |
Returns the number of threads that have been allocated to potentially work on the given type of task.
CAREFUL! This is not the number of threads that will be active at the same time. Use GetWorkerThreadCount() for that. This is the maximum number of threads that may jump in, if too many threads are blocked. This number will change dynamically at runtime to prevent deadlocks and it can grow very, very large.
|
static |
Returns the utilization (0.0 to 1.0) of the given thread. Note: This will only be valid, if FinishFrameTasks() is called once per frame.
Also optionally returns the number of tasks that were finished during the last frame.
|
static |
Returns whether the given Group id refers to a task group that has been finished already.
There is no time frame in which group IDs are valid. You may call this function at any time, even 10 minutes later, and it will correctly determine the results.
|
static |
A helper function to process task items in a parallel fashion by generating per-worker sub-ranges from an initial item array pointer. Given an array pointer 'taskItems' with elements of type ElemType, the following invocations are possible:
|
static |
A helper function to process task items in a parallel fashion and one-by-one (without global index). Given an array pointer 'taskItems' with elements of type ElemType, the following invocations are possible:
|
static |
A helper function to process task items in a parallel fashion and one-by-one (with global index). Given an array pointer 'taskItems' with elements of type ElemType, the following invocations are possible:
|
static |
Sets the target frame time that is supposed to not be exceeded.
|
static |
Sets the number of threads to use for the different task categories.
uiShortTasks and uiLongTasks must be at least 1 and should not exceed the number of available CPU cores. There will always be exactly one additional thread for file access tasks (plTaskPriority::FileAccess).
If uiShortTasks or uiLongTasks is smaller than 1, a default number of threads will be used for that type of work. This number of threads depends on the number of available CPU cores. If SetWorkThreadCount is never called, at all, the first time any task is started the number of worker threads is set to this default configuration. Unless you have a good idea how to set up the number of worker threads to make good use of the available cores, it is a good idea to just use the default settings.
|
static |
Blocks the current thread until the given delegate returns true.
If possible, prefer to use WaitForGroup() to wait for some task to finish, as that is the most efficient way. If not possible, prefer to use WaitForCondition() instead of rolling your own busy-loop for polling some state. WaitForCondition() will NOT put the current thread to sleep, but instead keep polling the delegate. However, in between, it will try to execute other tasks and if there are no tasks that it could take on, it will wake up another worker thread thus guaranteeing, that there are enough unblocked threads in the system to do all the work.
|
static |
Blocks until all tasks in the given group have finished.
If you need to wait for some other task to finish, this should always be the preferred method to do so. WaitForGroup will put the current thread to sleep and use thread signals to only wake it up again once the group is indeed finished. This is the most efficient way to wait for a task.