TTask<ResultType>
|
A handle of an actual task. It uses reference counting to manage the task's lifetime.
The task is created when it's launched.
Releasing the last user-held reference doesn't necessarily release the task as the system can still hold an internal reference used to execute the task.
FTask is an alias for tasks that do not return results (TTask);
|
TTask<ResultType>::IsValid()
|
The function:
bool TTask<ResultType>::IsValid() const;
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:
FTask Task;
check(!Task.IsValid());
Task = Launch(UE_SOURCE_LOCATION, [] {});
check(Task.IsValid());
Task = {}; // reset the task object
check(!Task.IsValid());
|
Task<ResultType>::Launch
|
Launches a task for asynchronous execution. In the Code example below launch is used on a task and returns its handle:
template<typename TaskBodyType>
TTask<TInvokeResult_T<TaskBodyType>> Launch(
const TCHAR* DebugName,
TaskBodyType&& TaskBody,
LowLevelTasks::ETaskPriority Priority =
LowLevelTasks::ETaskPriority::Normal
);
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.
template<typename TaskBodyType, typename PrerequisitesCollectionType>
TTask<TInvokeResult_T<TaskBodyType>> TTask<ResultType>::Launch(
const TCHAR* DebugName,
TaskBodyType&& TaskBody,
PrerequisitesCollectionType&& Prerequisites,
LowLevelTasks::ETaskPriority Priority =
LowLevelTasks::ETaskPriority::Normal
);
Parameters:
DebugName - a (preferably) unique name for task identification in debugger and profiler. UE_SOURCE_LOCATION macro can be used, that generates a string [Filename]:[Lineno] of the source location where it's used.
TaskBody - a callable object that will be executed asynchronously, e.g. a lambda, a function pointer or a class with operator();
Prerequisites - an iterable collection of TTask. Their result type is not required to match the result type of the task.
Priority - task priority that affects the order in which tasks are executed.
Example:
FTask Prerequisite1 = Launch(UE_SOURCE_LOCATION, []{});
FTask Prerequisite2 = Launch(UE_SOURCE_LOCATION, []{}, ETaskPriority::High);
FTask DependentTask = Launch(UE_SOURCE_LOCATION, []{}, Prerequisites(Prerequisite1, Prerequisite2));
TTask<bool> BoolTask = Launch(UE_SOURCE_LOCATION, []{ return true; });
template<typename... TaskTypes> TPrerequisites<TaskTypes...> Prerequisites(TaskTypes&... Tasks); is a helper function to pass a variable number of prerequisites to Launch() and FTaskEvent::AddPrerequisites() . For additional examples, you can observe the tasks: IsCompleted() , Wait() ,GetResult() .
|
TTask<ResultType>::IsCompleted
|
Returns true if the task is completed or is not valid.
bool TTask<ResultType>::IsCompleted() const;
A task is completed if its execution is finished and all its nested tasks are completed.
Example:
FTask Task;
check(Task.IsCompleted());
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.Wait();
check(Task.IsCompleted());
For additional examples, you can observe the tasks: Launch() , Wait() and GetResult() .
|
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 Wait() returns true. Returns true immediately if the task is not valid:
bool TTask<ResultType>::Wait(FTimespan Timeout);
template<typename TaskCollectionType>
bool Wait(const TaskCollectionType& Tasks, FTimespan InTimeout);
Example: FTask Task;
Task.Wait(); // returns immediately
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.Wait(FTimespan::FromMillisecond(3)); // blocks until the task is completed or waiting timed out
FTask AnotherTask = Launch(UE_SOURCE_LOCATION, []{});
TArray<FTask> Tasks{ Task, AnotherTask };
Wait(Tasks); // blocks until all tasks are completed
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:
FTask Task1 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task2 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task3 = Launch(UE_SOURCE_LOCATION, []{}, Task2);
Task3.Wait();
The sample above launches three tasks, where Task2 is a prerequisite of Task3 . Waiting for Task3 completion may retract Task3 and/or its prerequisite Task2 and execute them online, however this will not apply to Task1 .
|
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.
void TTask<ResultType>::BusyWait();
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.
bool TTask<ResultType>::BusyWait(FTimespan Timeout);
template<typename TaskCollectionType>
bool BusyWait(const TaskCollectionType& Tasks,
FTimespan InTimeout = FTimespan::MaxValue())
Before executing unrelated tasks, busy waiting first tries to retract the task that is waited for.
FTask Task;
Task.BusyWait(); // returns immediately
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.BusyWait(); // blocks until the task is completed, can execute other tasks while blocked
FTask AnotherTask = Launch(UE_SOURCE_LOCATION, []{});
TArray<FTask> Tasks{ Task, AnotherTask };
BusyWait(Tasks, FTimespan::FromMilliseconds(1));
// preceding line blocks until all tasks are completed or waiting timed out, can execute other tasks while blocked
|
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).
ResultType& TTask<ResultType>::GetResult();
This exists only for tasks with non-void ResultType.
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:
TTask<bool> BoolTask = Launch(UE_SOURCE_LOCATION, []{ return true; });
bool bResult = BoolTask.GetResult();
TTask<int32> IntTask;
// IntTask.GetResult(); - asserts, the task is invalid as it wasn't launched
|
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.
template<typename TaskType>
void AddNested(const TaskType& Nested);
Example:
FTask ParentTask = Launch(TEXT("Parent Task"),
[]
{
FTask NestedTask = Launch(TEXT("Nested Task"), []{});
AddNested(NestedTask);
}
);
|