目标
要想在另一个线程中执行代码,使用FRunnable是一种方式。而使用FAsyncTask
是另一种方式(这也是UE的DDC相关代码中所使用的方式)。
本篇尝试运行一个 FAsyncTask 的最简单的例子。
1. FAsyncTask 对于任务类的要求
FAsyncTask
是一个类模板:(定义在Runtime\Core\Public\Async\AsyncWork.h)
template<typename TTask>
class FAsyncTask
: public FAsyncTaskBase
{
...
TTask
是其类型参数,即“任务类”
一个比喻:FAsyncTask
是 “航班”,而 TTask
是这个航班的 “飞机”。(类似,RunnableThread是 “航班”,Runnable是 “飞机”)
FAsyncTask 对TTask
是有一定要求的,因为他会调用TTask
的一些函数,如果TTask
这些函数调用不到则编译不会通过:
这些函数是:
- TStatId GetStatId()
- void DoWork() (此处定义要运行的代码)
- bool CanAbandon()
- void Abandon()
2. 代码例子
参照源代码文件 Runtime\Core\Public\Async\AsyncWork.h 中开头的范例。
这里定义一个测试的任务类:
class FMyTaskWorker
{
public:
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FMyTaskWorker, STATGROUP_ThreadPoolAsyncTasks);
}
//在这里定义执行的代码:
void DoWork()
{
//作为测试,每1秒打印一次当前时间,执行5次
for (int i = 0; i < 5; i++)
{
FPlatformProcess::Sleep(1.0f);
UE_LOG(LogTemp, Warning, TEXT("YakSueTest: %s"), *FDateTime::Now().ToString());
}
}
bool CanAbandon()
{
return false;
}
void Abandon()
{
}
};
想要触发时,需要先创建对象,然后使用StartBackgroundTask
函数触发。为了测试,我这里在调用函数后打印一次log:
FAsyncTask<FMyTaskWorker>* AsyncTask = new FAsyncTask<FMyTaskWorker>();
AsyncTask->StartBackgroundTask();
UE_LOG(LogTemp, Warning, TEXT("YakSueTest: Function return"));
可以看到函数直接被返回,然后任务在另一个线程中逐步执行:
3*. 同步执行
如果在某些情况下,想要这个任务被同步执行(即在调用的线程中立即执行),则需要把StartBackgroundTask
函数换为StartSynchronousTask
函数:
FAsyncTask<FMyTaskWorker>* AsyncTask = new FAsyncTask<FMyTaskWorker>();
AsyncTask->StartSynchronousTask();
UE_LOG(LogTemp, Warning, TEXT("YakSueTest: Function return"));
如果是放在编辑器内触发按钮执行,则编辑器会卡住5秒执行这个任务,随后才返回函数。
总结
- 使用
FAsyncTask
时,要定义一个满足要求的任务类作为其类型参数。 - 执行时,使用
StartBackgroundTask
异步执行,使用StartSynchronousTask
来同步执行。