Tasks System resides in the UE::Tasks
namespace. To use Tasks System you will need to include the Tasks/Task.h
library. You can refer to the Tests/Tasks/TasksTest.cpp
class for usage examples.
The reference table below provides a few examples to the key functions of the Tasks System.
Reference | Description |
---|---|
TTask<ResultType>() |
A handle of an actual task. It uses reference counting to manage the task's lifetime.
|
TTask<ResultType>::IsValid() |
The function:
Returns true if the task handle references a task. A default-constructed task handle is "empty" and so is "not valid". A task is constructed when it's launched. For example:
|
Task<ResultType>::Launch |
Launches a task for asynchronous execution. In the Code example below launch is used on a task and returns its handle:
Prerequisites are other tasks that must be completed before the task that depends on them is executed. Once all prerequisites are completed, the task is automatically scheduled for execution.
Parameters:
Example:
|
TTask<ResultType>::IsCompleted |
Returns true if the task is completed or is not valid.
A task is completed if its execution is finished and all its nested tasks are completed. Example:
For additional examples, you can observe the tasks: |
TTask<ResultType>::Wait |
Blocks the current thread until the task(s) is completed or waiting timed out. Returns false on timeout. Waiting can take longer than the specified timeout value. The task(s) is completed if
Example:
If the task execution is not started yet (it's blocked by a prerequisite, or wasn't picked up by a worker thread yet), waiting for it will "retract" the task and execute it locally (inline). As the task execution hasn't started yet, the waiting thread would need to be blocked while a worker thread executes the task. Executing the task by the waiting thread is not slow process but can be faster, and doesn't occupy a worker thread. Task retraction follows task dependencies, so-called "deep task retraction". If task execution is blocked by prerequisites, task retraction will try to unblock the task by retracting and executing its prerequisites, recursively. If task retraction fails for any reason(the task execution already started) it falls back to blocking waiting. Example:
The sample above launches three tasks, where |
TTask<ResultType>::BusyWait |
Busy waiting for a task is the execution of other unrelated tasks while waiting for the task's completion. This can improve the system throughput but should be used cautiously. Busy waiting can take longer than blocking waiting and could affect latency-sensitive task-chains. In the function below, the task executes other ready for execution tasks until the task that is waited for is completed. Next, the task is completed after BusyWait Returns.
In the code sample below, we execute other ready for execution tasks until the task(s) that is waited for is completed, or waiting timed out. Next, we Return false on timeout. Waiting can take longer than the specified timeout value. The task(s) is completed if BusyWait returns true.
Before executing unrelated tasks, busy waiting first tries to retract the task that is waited for.
|
TTask<ResultType>::GetResult |
Returns a reference to an object returned by the task as a result of its execution (the value returned by task body execution).
If the task is completed, the call returns immediately. Otherwise, it blocks until the task is completed. The result object gets destroyed when the task object is destroyed, which is when the last reference to the task object is released. The call asserts if the task is not valid. Example:
|
AddNested() |
Registers the given task as "nested" to the "current" task (parent task). The current task is a task that is being executed by the current thread. The Parent task is not completed until all nested tasks are completed. Asserts if is called not from inside another task.
Example:
|
FTaskEvent
FTaskEvent shares a part of its API with TTask<ResultType>
. For example, IsValid()
, IsCompleted()
, waiting and busy-waiting API is the same. This section describes only FTaskEvent specific API.
Reference Task Event | Description |
---|---|
FTaskEvent Constructor |
Creates a task event object with the given debug name. In contrast with TTask
A task event must be triggered before it's destroyed. Example:
|
FTaskEvent::AddPrerequisites |
Adds other tasks (or task events) as prerequisites. Can be called only before triggering the task event. Only when all prerequisites are completed and the task event is triggered does it become "completed" ("signaling").
Example:
|
FTaskEvent::Trigger |
A task event is incomplete ("non-signaling") until it's triggered. Triggering a task event doesn't necessarily make it signaling, only when all its prerequisites are completed and the task event is triggered does it become completed. Every task event must be triggered. Otherwise, its destructor will assert that the task event is not completed.
|
FPipe
Pipes are lightweight non-copyable and non-movable objects. The construction of a pipe doesn't allocate dynamic memory and doesn't perform costly processing.
Reference Name | Description |
---|---|
FPipe constructor |
Constructs a pipe object with the given debug name. Debug name is used for debugging purposes, to identify a pipe object.
Pipes are lightweight non-copyable and non-movable objects. The construction of a pipe doesn't allocate dynamic memory and doesn't do any costly processing |
FPipe destructor |
Checks if the pipe has any non completed tasks. A pipe must not have any non completed tasks upon destruction. |
HasWork() |
Checks if the pipe has any non completed tasks. A pipe must not have any non-completed tasks upon destruction.
|
WaitUntilEmpty() |
This call will block until all pipe's tasks are completed.
Refer to the function |
Launch() |
Launches a task in the pipe. Tasks launched in the same pipe are executed not concurrently (one after another), but can be executed by different worker threads.
|
IsInContext() |
Returns true if called from inside a task that belongs to this pipe. Can be used to check if it's safe to access a shared resource protected by a pipe, such as when the code doesn't have scope of being executed by a piped task.
|