【UE4 C++ 基础知识】<14> 多线程——AsyncTask
概念
AsyncTask
- AsyncTask 系统是一套基于线程池的异步任务处理系统。每创建一个AsyncTas,都会被加入到线程池中进行执行
- AsyncTask 泛指
FAsyncTask
和FAutoDeleteAsyncTask
,一般声明为友元函数,FNonAbandonableTask 派生类作为模板 FNonAbandonableTask
是要继承的基类,不可被终止的任务,可以看作是任务执行体的抽象
FAsyncTask
- 模板类
DoWork()
实现具体任务,自定义类作为模板参数- FAsyncTask 初始化后,默认添加到线程池FQueuedThreadPool。可以指定其他线程池
StartBackgroundTask()
将任务扔到线程池中去执行StartSynchronousTask()
直接在当前线程执行
EnsureCompletion()
可以等待任务完成- 执行结束需要手动停止或删除任务
FAutoDeleteAsyncTask
- 与 FAsyncTask 类似
- 执行结束自动删除伍。执行完成后,会通过线程池的 Destroy 函数删除,或者 DoWork 完成后删除
FQueuedThreadPool线程池
- FQueuedThreadPool: 虚基类,定义线程池常用的接口。FQueueThreadPoolBase 继承FQueuedThreadPool,实现具体的方法。
- FQueueThreadPoolBase 维护了多个线程FQueuedThread与多个任务队列IQueuedWork
- TArray<IQueuedWork*> QueuedWork(要被执行的任务)
- TArray<FQueuedThread*> QueuedThreads(空闲的线程)
- TArray<FQueuedThread*> AllThreads(所有的线程)。
- 线程池里的线程都是FQueuedThread类型,FQueuedThread是继承自FRunnable的线程执行体
- FRunnableThread 表示线程本身,该类会派生出平台相关的子类
FEvent
- FEvent: 虚基类,提供了事件操作的接口,用于线程的挂起/唤醒(Wait()/Trigger())
使用方式
简单使用方式 Lambda
- 可指定线程
- 可根据指定线程用于多线程调用主线程里的东西
AsyncTask(ENamedThreads::GameThread, [=]() { // Do Something });
手动销毁方式:FNonAbandonableTask 与 FAsyncTask
-
SimpleAsyncTask 类
class SimpleAsyncTask :FNonAbandonableTask { FString m_TaskName; int32 m_MaxNumber; friend class FAsyncTask<SimpleAsyncTask>; public: // 构造函数 SimpleAsyncTask(const FString& TaskName, int32 MaxNumber) : m_TaskName(TaskName), m_MaxNumber(MaxNumber) {} // 析构函数 ~SimpleAsyncTask() { UE_LOG(LogTemp, Warning, TEXT("Task[%s] End"), *m_TaskName); } // 具体任务逻辑执行 void DoWork() { UE_LOG(LogTemp, Warning, TEXT("Task[%s] Start"), *m_TaskName); int CurrentNum = 0; while (CurrentNum < m_MaxNumber) { CurrentNum++; UE_LOG(LogTemp, Warning, TEXT("Task[%s] CurrentNum:%d"), *m_TaskName, CurrentNum); } } // 固定写法,本类将作为函数参数 FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(SimpleAsyncTask, STATGROUP_ThreadPoolAsyncTasks); } };
-
调用任务的Actor——AAsyncTaskActor
UFUNCTION(BlueprintCallable) void CreateAsyncTask(const FString& TaskName, int32 MaxNumber);
void AAsyncTaskActor::CreateAsyncTask(const FString& TaskName, int32 MaxNumber) { UE_LOG(LogTemp, Warning, TEXT("Task[%s] Created"), *TaskName); FAsyncTask<SimpleAsyncTask>* MyTask = new FAsyncTask<SimpleAsyncTask>(TaskName, MaxNumber); MyTask->StartBackgroundTask(); // MyTask->StartSynchronousTask; 在当前线程执行,可能会导致主线程阻塞 // MyTask->IsDone() 可以配合定时器检测是否完成任务 //等待任务完成后,进行手动删除 MyTask->EnsureCompletion(); delete MyTask; MyTask = nullptr; }
自动销毁方式:FNonAbandonableTask 与 FAutoDeleteAsyncTask
-
AutoDeleteSimpleAsyncTask 类
class AutoDeleteSimpleAsyncTask :FNonAbandonableTask { FString m_TaskName; int32 m_MaxNumber; friend class FAutoDeleteAsyncTask<AutoDeleteSimpleAsyncTask>; public: // 构造函数 AutoDeleteSimpleAsyncTask(const FString& TaskName, int32 MaxNumber) : m_TaskName(TaskName), m_MaxNumber(MaxNumber) {} // 析构函数 ~AutoDeleteSimpleAsyncTask() { UE_LOG(LogTemp, Warning, TEXT("Task[%s] End"), *m_TaskName); } // 具体任务逻辑执行 void DoWork() { UE_LOG(LogTemp, Warning, TEXT("Task[%s] Start"), *m_TaskName); int CurrentNum = 0; while (CurrentNum < m_MaxNumber) { CurrentNum++; UE_LOG(LogTemp, Warning, TEXT("AutoDeleteTask[%s] CurrentNum:%d"), *m_TaskName, CurrentNum); } } // 固定写法,本类将作为函数参数 FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(SimpleAsyncTask, STATGROUP_ThreadPoolAsyncTasks); } };
-
调用任务的Actor——AAsyncTaskActor
UFUNCTION(BlueprintCallable) void CreateAutoDeleteAsyncTask(const FString& TaskName, int32 MaxNumber);
void AAsyncTaskActor::CreateAutoDeleteAsyncTask(const FString& TaskName, int32 MaxNumber) { UE_LOG(LogTemp, Warning, TEXT("AutoDeleteTask[%s] Created"), *TaskName); // 任务完成后,自动删除 (new FAutoDeleteAsyncTask<AutoDeleteSimpleAsyncTask>(TaskName, MaxNumber))->StartSynchronousTask(); }
参考
- FAsyncTask
- FAutoDeleteAsyncTask
- FNonAbandonableTask
- Legacy/Using AsyncTasks
- 《Exploring in UE4》多线程机制详解[原理分析]
- \EpicGames\UE_4.26\Engine\Source\Runtime\Core\Public\Async\AsyncWork.h
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!