TTask<ResultType>
|
실제 태스크의 핸들입니다. 레퍼런스 카운트로 태스크의 수명을 관리합니다.
태스크는 실행과 동시에 생성됩니다.
마지막 사용자가 보유한 레퍼런스를 해제하더라도, 시스템에서 태스크 실행에 필요한 내부 레퍼런스를 계속 보유하기 때문에 태스크를 해제할 필요는 없습니다.
FTask는 결과를 반환하지 않는 태스크(TTask)의 다른 이름입니다.
|
TTask<ResultType>::IsValid()
|
함수:
bool TTask<ResultType>::IsValid() const;
태스크 핸들이 태스크를 참조할 경우 true를 반환합니다. 디폴트로 생성된 태스크 핸들은 ‘비어 있으므로' ‘유효하지 않습니다.' 태스크는 실행과 동시에 생성됩니다. 예를 들면 다음과 같습니다.
FTask Task;
check(!Task.IsValid());
Task = Launch(UE_SOURCE_LOCATION, [] {});
check(Task.IsValid());
Task = {}; // reset the task object
check(!Task.IsValid());
|
Task<ResultType>::Launch
|
비동기 실행을 위해 태스크를 실행합니다. 아래 코드 예시에서는 실행 기능을 태스크에 사용한 뒤 핸들을 반환합니다.
template<typename TaskBodyType>
TTask<TInvokeResult_T<TaskBodyType>> Launch(
const TCHAR* DebugName,
TaskBodyType&& TaskBody,
LowLevelTasks::ETaskPriority Priority =
LowLevelTasks::ETaskPriority::Normal
);
종속된 태스크가 실행되기 전에 다른 태스크부터 완료해야 합니다. 모든 선행 태스크가 완료되면 자동으로 태스크 실행을 예약합니다.
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
);
파라미터:
DebugName - 디버거 및 프로파일러에서 태스크를 식별할 때 사용되는 이름입니다. 되도록이면 고유한 이름을 사용합니다. UE_SOURCE_LOCATION 매크로를 사용할 수 있습니다. 이 매크로는 매크로가 사용된 소스 위치에 [Filename]:[Lineno] 스트링을 생성합니다.
TaskBody - 비동기적으로 실행되는 호출 가능 오브젝트입니다(예: 람다, 함수 포인터 또는 연산자()가 있는 클래스).
Prerequisites - 반복 가능한 TTask의 컬렉션입니다. 결과 타입이 태스크의 결과 타입과 일치할 필요는 없습니다.
Priority - 태스크의 실행 순서에 영향을 미치는 태스크 우선순위입니다.
예시:
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); 는 Prerequisites의 변수 수를 Launch() 와 FTaskEvent::AddPrerequisites() 에 전달하는 헬퍼 함수입니다. 추가 예시로 Launch(), Wait(), GetResult() 태스크를 관찰할 수 있습니다.
|
TTask<ResultType>::IsCompleted
|
태스크가 완료되었거나 유효하지 않으면 true를 반환합니다.
bool TTask<ResultType>::IsCompleted() const;
만약 태스크의 실행이 끝나고 모든 중첩된 태스크가 완료되면 태스크가 완료됩니다.
예시:
FTask Task;
check(Task.IsCompleted());
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.Wait();
check(Task.IsCompleted());
추가 예시로 Launch(), Wait(), GetResult() 태스크를 관찰할 수 있습니다.
|
TTask<ResultType>::Wait
|
태스크가 완료되거나 타임아웃되기를 기다렸다가 현재 스레드를 블록합니다. 타임아웃 시 false를 반환합니다. 지정된 타임아웃 값보다 대기가 길어질 수 있습니다. Wait() 에서 true를 반환하면 태스크가 완료됩니다. 태스크가 유효하지 않으면 즉시 true를 반환합니다.
bool TTask<ResultType>::Wait(FTimespan Timeout);
template<typename TaskCollectionType>
bool Wait(const TaskCollectionType& Tasks, FTimespan InTimeout);
예시: FTask Task;
Task.Wait(); // 즉시 반환
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.Wait(FTimespan::FromMillisecond(3)); // 태스크가 완료되거나 타임아웃되기를 기다렸다가 블록
FTask AnotherTask = Launch(UE_SOURCE_LOCATION, []{});
TArray<FTask> Tasks{ Task, AnotherTask };
Wait(Tasks); // 모든 태스크가 완료될 때까지 블록
선행 태스크에 의해 블록되었거나 워커 스레드에서 아직 선택하지 않아 태스크 실행이 아직 시작되지 않은 경우, 태스크를 ‘철회'하거나 로컬로 실행할 때까지 대기합니다(인라인). 태스크 실행이 아직 시작되지 않았으므로, 워커 스레드가 태스크를 실행하는 동안 대기 스레드를 블록해야 합니다. 대기 스레드로 태스크를 실행하면 느리지 않고 빠른 프로세스를 진행할 수 있으며 워커 스레드를 침범하지도 않습니다.
태스크 철회 작업은 ‘딥 태스크 철회'라는 태스크 종속성을 따릅니다. 태스크 실행이 선행 태스크에 의해 차단당할 경우, 태스크 철회는 선행 태스크를 철회하고 다시 실행하여 차단을 풀려고 시도합니다.
테스크 실행이 이미 시작했거나 모종의 이유로 태스크 철회에 실패할 경우 대기 블록으로 돌아갑니다.
예시:
FTask Task1 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task2 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task3 = Launch(UE_SOURCE_LOCATION, []{}, Task2);
Task3.Wait();
위 샘플은 세 개의 태스크를 실행하며, 여기서 Task2 는 Task3 의 선행 태스크가 됩니다. Task3 의 완료를 기다리는 동안 Task3 , 혹은 Task3 의 선행 태스크인 Task2 를 철회하고 온라인으로 실행할 수도 있지만, Task1 에는 아무 일도 일어나지 않습니다.
|
TTask<ResultType>::BusyWait
|
바쁜 대기(Busy Waiting)는 태스크가 완료되기를 기다리는 동안 관련이 없는 다른 태스크를 실행한다는 뜻입니다. 시스템 처리량은 향상되지만 신중하게 사용해야 합니다. 바쁜 대기는 대기 블록보다 오래 걸릴 수 있으며, 지연시간에 민감한 태스크 체인에 영향을 미칠 수 있습니다.
아래 함수에서 태스크는 대기 중인 태스크가 완료될 때까지 실행 준비를 마친 다른 태스크를 실행합니다. 이 태스크는 BusyWait 반환 후 완료됩니다.
void TTask<ResultType>::BusyWait();
아래 코드 샘플에서 대기 중인 태스크가 완료되었거나 대기 시간이 끝날 때까지 실행 준비를 마친 다른 태스크를 실행합니다. 타임아웃 시 false를 반환합니다. 지정된 타임아웃 값보다 대기가 길어질 수 있습니다. 태스크는 BusyWait에서 true를 반환하면 완료됩니다.
bool TTask<ResultType>::BusyWait(FTimespan Timeout);
template<typename TaskCollectionType>
bool BusyWait(const TaskCollectionType& Tasks,
FTimespan InTimeout = FTimespan::MaxValue())
관련이 없는 태스크를 실행하기 전에 바쁜 대기를 사용하면 대기 중인 태스크의 철회를 우선적으로 시도합니다.
FTask Task;
Task.BusyWait(); // 즉시 반환
Task = Launch(UE_SOURCE_LOCATION, []{});
Task.BusyWait(); // 태스크가 완료될 때까지 블록. 블록된 동안 다른 태스크 실행 가능
FTask AnotherTask = Launch(UE_SOURCE_LOCATION, []{});
TArray<FTask> Tasks{ Task, AnotherTask };
BusyWait(Tasks, FTimespan::FromMilliseconds(1));
// 모든 태스크가 완료되거나 타임아웃을 기다렸다가 선행 행 블록. 블록된 동안 다른 태스크 실행 가능
|
TTask<ResultType>::GetResult
|
태스크에서 실행의 결과로 반환한 오브젝트의 레퍼런스를 반환합니다. 태스크의 바디 실행으로 인해 반환된 값입니다.
ResultType& TTask<ResultType>::GetResult();
void가 아닌 ResultType이 있는 태스크에만 존재합니다.
태스크가 완료되면 호출 시 결과를 즉시 반환합니다. 완료되지 않으면 태스크를 진행하는 동안 블록합니다.
태스크 오브젝트가 소멸되면 결과 오브젝트도 소멸됩니다. 이때 태스크 오브젝트의 마지막 레퍼런스가 해제됩니다.
태스크가 유효하지 않으면 어서트를 호출합니다.
예시:
TTask<bool> BoolTask = Launch(UE_SOURCE_LOCATION, []{ return true; });
bool bResult = BoolTask.GetResult();
TTask<int32> IntTask;
// IntTask.GetResult(); - 태스크가 시작되지 않아 유효하지 않으므로 어서트 호출
|
AddNested()
|
주어진 태스크를 ‘현재' 태스크(부모 태스크)에 ‘중첩됨'으로 등록합니다. 현재 태스크(Current Task) 는 현재 스레드에서 실행된 태스크입니다.
부모 태스크(Parent Task) 는 모든 중첩 태스크가 완료될 때까지 완료되지 않습니다.
다른 태스크에서 호출되지 않으면 어서트가 호출됩니다.
template<typename TaskType>
void AddNested(const TaskType& Nested);
예시:
FTask ParentTask = Launch(TEXT("Parent Task"),
[]
{
FTask NestedTask = Launch(TEXT("Nested Task"), []{});
AddNested(NestedTask);
}
);
|