Runnable线程和切换线程
首先模拟创造线程的过程,创建一个接口类,预留一个函数
// This class does not need to be modified. UINTERFACE(MinimalAPI) class UTaskInterface : public UInterface { GENERATED_BODY() }; /** * */ class ADVANCEPROJECT_API ITaskInterface { GENERATED_BODY() // Add interface functions to this class. This is the class that will be inherited to implement this interface. public: virtual void DoWork(){} };
然后就是现线程类,继承FRunnable
DECLARE_DELEGATE(FThreadDeclare) class ADVANCEPROJECT_API ThreadTask : public FRunnable { public: ThreadTask(); FThreadDeclare* MainThreadDeclare; virtual uint32 Run(); void CreateThread(ITaskInterface* NewTaskInter); ~ThreadTask(); private: ITaskInterface* TaskInterface; FRunnableThread* Task_Thread; };
CPP:
ThreadTask::ThreadTask() { TaskInterface=nullptr; }
//新线程开启后,会运行重写的Run方法 uint32 ThreadTask::Run() { UE_LOG(LogTemp,Log,TEXT("Run")); if (TaskInterface) {
//新线程 TaskInterface->DoWork(); //这里插入一个线程方法,在他准备完毕后,会执行绑定的方法,会回到这个方法所规定线程,如果他绑定过的话。 FGraphEventRef taskRef = FFunctionGraphTask::CreateAndDispatchWhenReady([&]() { MainThreadDeclare->ExecuteIfBound(); },TStatId(),nullptr,ENamedThreads::GameThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(taskRef); } return 0; }
//真正意义上的开一个新线程 void ThreadTask::CreateThread(ITaskInterface* NewTaskInter) { TaskInterface = NewTaskInter; Task_Thread = FRunnableThread::Create(this,TEXT("HelloWorld"),0,TPri_Normal); } ThreadTask::~ThreadTask() { }
NewInter = new ITaskInterface(); NewTask = new ThreadTask(); //绑定代理,将主线程的一个函数绑定给他的代理 NewTask->MainThreadDeclare->BindUObject(this,&AAdvanceProjectGameModeBase::Print_V); //开辟线程,运行newtask的run() NewTask->CreateThread(NewInter);
图例:
在create线程前,绑定工作还在主线程做

到run这里,就变成自己的线程名了。

然后在切换线程部分,在执行函数准备完成之前,依旧还是在我们的线程里工作。

准备完毕,进入代理函数,回到主线程

GraphTask线程
这四个接口方法为固定形式
#pragma once #include "CoreMinimal.h" class FTaskGraph { private: float _Str; public: static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } FORCEINLINE TStatId GetStatId() { RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph, STATGROUP_TaskGraphTasks); } void DoTask(ENamedThreads::Type CurrentThread, FGraphEventRef Subsequents) { UE_LOG(LogTemp, Log, TEXT("HelloWorld %f"),_Str); } static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; } FTaskGraph(float NewStr): _Str(NewStr) { } };
//支持构造方法传递参数
TGraphTask<FTaskGraph>::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(7.7f);
AsyncTask线程
#pragma once #include "CoreMinimal.h" class FMyAsyncTask : public FNonAbandonableTask { friend class FAsyncTask<FMyAsyncTask>; int32 InstanceInt; public: FMyAsyncTask(int32 NewInt): InstanceInt(NewInt) { } void DoWork() { GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("DoWork %d")); UE_LOG(LogTemp,Log,TEXT("DoWork %d"),InstanceInt); } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FMyAsyncTask,STATGROUP_ThreadPoolAsyncTasks); } };
FAsyncTask<FMyAsyncTask>* MyAsync = new FAsyncTask<FMyAsyncTask>(666);
//选择是否为顺序执行还是异步执行,这里是异步 MyAsync->StartBackgroundTask(); if (MyAsync->IsDone()) { delete MyAsync; MyAsync = nullptr; }
三种不同点
1.Runnable,是真正意义上的开新线程,开启的过程比较消耗性能,这个线程可以用作大型复杂的计算,比如与数据库、服务器的交互
2.GraphTask线程可以确定自己的任务顺序,其中一个参数可以放前置条件,只有前置条件完成后,才会运行本身![]()
3.为了避免不必要的消耗,可以使用AsyncTask线程从线程池里调用,直接使用。也不需要像GraphTask一样创建一个函数类去初始化。


另外,只能在主线程完成的任务绝对不能放到其他线程执行。


浙公网安备 33010602011771号