Tasks System の参照

Tasks System で利用可能なさまざまなタスクへの参照です。

Choose your operating system:

Windows

macOS

Linux

コンテンツ

Tasks System は UE::Tasks 名前空間に存在します。Tasks System を使用するには、 Tasks/Task.h ライブラリをインクルードする必要があります。使用例については、 Tests/Tasks/TasksTest.cpp クラスを参照してください。 Tasks System の主要関数について、いつくかの例を以下の参照の表に示します。

参照

説明

TTask<ResultType>

実際のタスクのハンドル。タスクの存続期間を管理するための参照カウントを使用します。

実際のタスクのハンドル。 参照カウントを使用して、タスクの有効期間を管理します。

  • タスクは起動時に作成されます。

  • システムではタスクの実行に使用する内部参照を保持できるため、ユーザーが保持する最後の参照を解放しても、必ずしもタスクが解放されるわけではありません。

  • FTask は結果を返さないタスクのエイリアスです (TTask)。

TTask<ResultType>::IsValid()

関数

bool TTask<ResultType>::IsValid() const;

タスク ハンドルがタスクを参照している場合に true を返します。デフォルトの構築されたタスク ハンドルは「empty」であり、「無効」です。タスクは起動時に構築されます。次はその例です。次に例を示します。

FTask Task;
check(!Task.IsValid());
Task = Launch(UE_SOURCE_LOCATION, [] {});
check(Task.IsValid());
Task = {}; // reset the task object
check(!Task.IsValid());

Task<ResultType>::Launch

非同期で実行するためにタスクを起動します。以下のコード例では 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 - 呼び出し可能なオブジェクトであり、非同期で実行されます。たとえば、関数ポインタまたは演算子 () を持つクラスである lambda です。

  • 前提条件 - イテレーション可能な 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); は、 Launch()FTaskEvent::AddPrerequisites() に前提条件の変数の数を渡すヘルパー関数です。追加の例は、次のタスクで確認できます。IsCompleted(), 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(); // 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

タスクの実行がまだ開始されない (前提条件によってブロックされているか、またはワーカー スレッドによってまだ選択されていない) 場合にタスクを待機すると、そのタスクは「退避」され、ローカル (インライン) で実行されます。タスクの実行はまだ開始されていないため、ワーカー スレッドがタスクを実行する間、待機中のスレッドはブロックする必要があります。待機中のスレッドによるタスクの実行は低速な処理ではなく、高速にすることができ、ワーカー スレッドを占有しません。 タスクの退避は、タスクの依存関係に従って行われ、「詳細なタスク退避」と呼ばれています。タスクの実行が前提条件によってブロックされた場合、タスクの退避では、再帰的に前提条件を退避して実行することで、そのタスクのブロック解除を試行します。 タスクの退避が何らかの理由 (タスクの実行がすでに開始されていたなど) で失敗した場合は、ブロック状態の待機にフォールバックします。

例:

FTask Task1 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task2 = Launch(UE_SOURCE_LOCATION, []{});
FTask Task3 = Launch(UE_SOURCE_LOCATION, []{}, Task2);
Task3.Wait();

上記のサンプルでは、3 つのタスクが起動されます。ここで、 Task2Task3 の前提条件となっています。Task3 の完了を待機すると、 Task3 やその前提条件である Task2 が退避され、オンラインで実行される可能性がありますが、これは Task1 には適用されません。

TTask<ResultType>::BusyWait

タスクをビジー状態で待機すると、そのタスクの完了を待機する間に他の関連しないタスクが実行されます。これによってシステムのスループットが向上する場合がありますが、これを使用する場合は注意が必要です。ビジー状態の待機はブロック状態の待機よりも時間がかかる可能性があり、レイテンシーに左右されやすいタスクチェーンに影響を与える場合があります。 以下の関数では、待機しているタスクが完了するまで、実行準備が完了した他のタスクが実行されます。その後、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(); // 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

タスクの実行の結果としてタスクによって返されたオブジェクトへの参照 (タスク ボディの実行によって返される値) を返します。

ResultType& TTask<ResultType>::GetResult();

これは、非 void 型の ResultType のタスクのためにのみ用意されています。

タスクが完了すると、この呼び出しに直ちに戻ります。完了しない場合、タスクが完了するまでブロックが継続します。 タスク オブジェクトが破棄されると、結果のオブジェクトは破棄されます。これは、タスク オブジェクトへの最後の参照の解放時に行われます。 タスクが無効な場合、この呼び出しではアサーションが行われます。

例:

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()

与えられたタスクを「現在の」タスク (親タスク) に対して「ネスト」して登録します。この 現在のタスク は現在のスレッドによって実行中のタスクです。

親タスク は、ネストされたすべてのタスクが完了するまで完了しません。

別の内部のタスクから呼び出された場合にはアサーションを行いません。

template<typename TaskType>
void AddNested(const TaskType& Nested);

例:

FTask ParentTask = Launch(TEXT("Parent Task"),
    []
    {
        FTask NestedTask = Launch(TEXT("Nested Task"), []{});
        AddNested(NestedTask);
}
);

FTaskEvent

FTaskEvent は、API の一部を TTask<ResultType> と共有しています。たとえば、 IsValid()IsCompleted() 、待機、およびビジー状態の待機の API は同じです。このセクションでは、FTaskEvent に固有の API のみについて説明します。

参照タスク イベント

説明

FTaskEvent Constructor

与えられたデバッグ名でタスク イベント オブジェクトを作成します。TTask とは対照的に、タスク イベントは、コンストラクション後に「有効」となり、IsValid() == true かつ未完了で IsCompleted() == false となります。デバッグ名は、デバッグ目的でタスク イベント オブジェクトを特定するために使用されます。

explicit FTaskEvent::FTaskEvent(const TCHAR* DebugName);

タスク イベントは、破棄される前にトリガーする必要があります。

例:

FTaskEvent TaskEvent{ UE_SOURCE_LOCATION };
check(TaskEvent.IsValid());
check(!TaskEvent.IsCompleted());
TaskEvent.Trigger();
check(TaskEvent.IsCompleted());

与えられたデバッグ名でパイプ オブジェクトを作成します。デバッグ名は、デバッグ目的でパイプ オブジェクトを特定するために使用されます。

FPipe::FPipe(const TCHAR* DebugName);

パイプは、軽量なコピー不可かつ移動不可のオブジェクトです。パイプを作成しても、動的メモリは割り当てられず、負荷が高い処理は実行されません。

FTaskEvent::AddPrerequisites

他のタスク (またはタスク イベント) を前提条件として追加します。タスク イベントのトリガー前にのみ呼び出すことができます。すべての前提条件が完了済みかつタスク イベントがトリガー済みの場合にのみ、「完了」(「シグナリング」) となります。

template<typename PrerequisitesType>
void FTaskEvent::AddPrerequisites(const PrerequisitesType& Prerequisites);

例:

FTaskEvent TaskEvent{ TEXT("TaskEvent") };

TArray<FTask> Prereqs
{ 
    Launch(TEXT("Task A"), [] {}), 
    Launch(TEXT("Task B"), [] {}) 
};
TaskEvent.AddPrerequisites(Prereqs);

FTask TaskC = Launch(TEXT("Task C"), [] {});
FTask TaskD = Launch(TEXT("Task D"), [] {});
TaskEvent.AddPrerequisites(Prerequisites(TaskC, TaskD));

TaskEvent.Trigger();

FTaskEvent::Trigger

タスク イベントはトリガーされるまで未完了 (「非シグナリング」) です。タスク イベントをトリガーしても、必ずしもシグナリングになるわけではありません。すべての前提条件が完了済みかつタスク イベントがトリガー済みの場合にのみ、「完了」(「シグナリング」) となります。

すべてのタスク イベントは、トリガーする必要があります。そうしないと、デストラクタによって、タスク イベントが完了済みかどうかのアサーションが行われます。

void FTaskEvent::Trigger();

FPipe

パイプは、軽量なコピー不可かつ移動不可のオブジェクトです。パイプを作成しても、動的メモリは割り当てられず、負荷が高い処理は実行されません。

参照名

説明

FPipe constructor

与えられたデバッグ名でタスク イベント オブジェクトを作成します。TTask とは対照的に、タスク イベントは、コンストラクション後に「有効」となり、IsValid() == true かつ未完了で IsCompleted() == false となります。デバッグ名は、デバッグ目的でタスク イベント オブジェクトを特定するために使用されます。

explicit FTaskEvent::FTaskEvent(const TCHAR* DebugName);

タスク イベントは、破棄される前にトリガーする必要があります。

例:

FTaskEvent TaskEvent{ UE_SOURCE_LOCATION };
check(TaskEvent.IsValid());
check(!TaskEvent.IsCompleted());
TaskEvent.Trigger();
check(TaskEvent.IsCompleted());

与えられたデバッグ名でパイプ オブジェクトを作成します。デバッグ名は、デバッグ目的でパイプ オブジェクトを特定するために使用されます。

FPipe::FPipe(const TCHAR* DebugName);

パイプは、軽量なコピー不可かつ移動不可のオブジェクトです。パイプを作成しても、動的メモリは割り当てられず、負荷が高い処理は実行されません。

FPipe destructor

パイプに未完了のタスクがないかどうかをチェックします。パイプの破棄時に未完了のタスクを残したままにはできません。

HasWork()

パイプに未完了のタスクがないかどうかをチェックします。パイプの破棄時に未完了のタスクを残したままにはできません。

bool FPipe::HasWork() const;

WaitUntilEmpty()

この呼び出しは、すべてのパイプのタスクが完了するまでブロックを行います。

void FPipe::WaitUntilEmpty();

追加の例については、関数 HasWork() を参照してください。

Launch()

パイプ内のタスクを起動します。同じパイプで起動されたタスクは、同時に実行されるわけではありません (順次実行されます)。ただし、異なるワーカー スレッドで実行できます。

template<typename TaskBodyType>
TTask<TInvokeResult_T<TaskBodyType>> FPipe::Launch(
const TCHAR* InDebugName, 
TaskBodyType&& TaskBody,                            
LowLevelTasks::ETaskPriority Priority = LowLevelTasks::ETaskPriority::Default
);

template<typename TaskBodyType, typename PrerequisitesCollectionType>
TTask<TInvokeResult_T<TaskBodyType>> FPipe::Launch(
const TCHAR* InDebugName, 
TaskBodyType&& TaskBody,                        
PrerequisitesCollectionType&& Prerequisites,
LowLevelTasks::ETaskPriority Priority = LowLevelTasks::ETaskPriority::Default
);

IsInContext()

このパイプに属するタスクの内部から呼び出された場合、true を返します。パイプされたタスクによって実行中のスコープがコードに含まれない場合など、パイプによって保護された共有リソースにアクセスするのが安全かどうかをチェックするために使用できます。

bool FPipe::IsInContext() const;
タグ