编程语言
首页 > 编程语言> > 【UE4 C++ 基础知识】<13> 多线程——TaskGraph

【UE4 C++ 基础知识】<13> 多线程——TaskGraph

作者:互联网

概述

TaskGraph 类定义

模块构成

自定义的任务必须要满足 TGraphTask 中对 Task 的接口需求

TaskGraph 简单实现

了解任务的创建

在上一小节中,我们可以使用以下代码创建任务

FGraphEventRef GraphEventRef = TGraphTask<FTaskGraph_SimpleTask>::CreateTask().ConstructAndDispatchWhenReady(ThreadName); // 创建任务立即执行
TGraphTask<FTaskGraph_SimpleTask>*  GraphTask = TGraphTask<FTaskGraph_SimpleTask>::CreateTask().ConstructAndHold(ThreadName); // 创建任务挂起,等待 unlock() 触发任务执行

TaskGraph 并行任务

具有依赖关系的并行任务

image

image

派发任务

image

image

C++代码

#pragma once
#include "CoreMinimal.h"
#include "TaskGraph_SimpleTask.generated.h"

DECLARE_DELEGATE_OneParam(FGraphTaskDelegate,const FString&); // 单播委托

USTRUCT(BlueprintType)
struct FTaskGraphItem {													// 结构体用来传参
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(BlueprintReadWrite)
		FString m_ThreadName;											// 线程名称

	FGraphEventRef m_GraphEventRef;										// 自动执行的任务
	TGraphTask<class FTaskGraphWithPrerequisitesAndChild>* m_GraphTask; // 需要触发执行的任务

	// 构造函数
	FTaskGraphItem(FString ThreadName = TEXT("None"), FGraphEventRef GraphEventRef = nullptr, TGraphTask<class FTaskGraphWithPrerequisitesAndChild>* GraphTask = nullptr)
		:m_ThreadName(ThreadName), m_GraphEventRef(GraphEventRef), m_GraphTask(GraphTask) {}

	~FTaskGraphItem()
	{
		m_GraphEventRef = nullptr;
		m_GraphTask = nullptr;
	}
};

class FTaskGraph_SimpleTask  // 作为具体执行的任务
{
	FString m_ThreadName;
	FGraphTaskDelegate m_GraphTaskDelegate; 

public:
	FTaskGraph_SimpleTask(const FString& ThreadName, FGraphTaskDelegate GraphTaskDelegate) 
		: m_ThreadName(ThreadName), m_GraphTaskDelegate(GraphTaskDelegate) {}
	~FTaskGraph_SimpleTask(){}

	// 固定写法
	FORCEINLINE TStatId GetStatId() const {
		RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph_SimpleTask, STATGROUP_TaskGraphTasks);
	}

	// 指定在主线程,因为用到 AActor 蓝图里的函数
	static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::GameThread; }

	// 后续执行模式
	static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }

	// 线程逻辑执行函数
	void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
	{
		check(IsInGameThread()); //确认是否在主线程
		FString message = FString::Printf(TEXT("SimpleTaskTask[%s] execute the GraphTaskDelegate!"), *m_ThreadName);
		m_GraphTaskDelegate.ExecuteIfBound(message);
		//UE_LOG(LogTemp, Warning, TEXT("SimpleTaskTask[%s] execute!"), *m_ThreadName);
	}
};

class FTaskGraphWithPrerequisitesAndChild  // 作为通用任务,可作为依赖事件的任务,也可作为子任务
{

	FString m_ThreadName;	
	TArray<TGraphTask<FTaskGraphWithPrerequisitesAndChild>*> m_ChildGraphTask;	// 子任务数组
	FGraphTaskDelegate m_GraphTaskDelegate; // 单播委托

public:
	// 构造函数
	FTaskGraphWithPrerequisitesAndChild(const FString& ThreadName, const TArray<TGraphTask<FTaskGraphWithPrerequisitesAndChild>*>& ChildTask, FGraphTaskDelegate GraphTaskDelegate)
		: m_ThreadName(ThreadName), m_ChildGraphTask(ChildTask), m_GraphTaskDelegate(GraphTaskDelegate) {}
	
	~FTaskGraphWithPrerequisitesAndChild() {}

	// 固定写法
	FORCEINLINE TStatId GetStatId() const {
		RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraphWithPrerequisitesAndChild, STATGROUP_TaskGraphTasks);
	}

	// 指定在哪个线程运行
	static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; }

	// 后续执行模式
	static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }

	// 线程逻辑执行函数
	void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
	{ 

		UE_LOG(LogTemp, Warning, TEXT("Task[%s] Begin!"), *m_ThreadName);
		// 执行子任务,此处通用任务作为子任务
		if (m_ChildGraphTask.Num()>0)
		{
			for (auto GraphTaskItem : m_ChildGraphTask)
			{
				GraphTaskItem->Unlock();  // 唤醒子任务
				MyCompletionGraphEvent->DontCompleteUntil(GraphTaskItem->GetCompletionEvent());				
			}
			// 如有需要,可设法检测所有子任务是否都完成
		}

		// 创建并执行子任务,本处作为具体执行的任务
		MyCompletionGraphEvent->DontCompleteUntil(TGraphTask<FTaskGraph_SimpleTask>::CreateTask().ConstructAndDispatchWhenReady(m_ThreadName, m_GraphTaskDelegate));
		UE_LOG(LogTemp, Warning, TEXT("Task[%s] End!"), *m_ThreadName);
	}
};
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TaskGraph_SimpleTask.h"
#include "TaskGraphActor.generated.h"

UCLASS()
class TIPS_API ATaskGraphActor : public AActor
{
	GENERATED_BODY()	
public:	
	ATaskGraphActor();
protected:
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// 创建任务
	UFUNCTION(BlueprintCallable)
		FTaskGraphItem CreateGraphTask(const FString& ThreadName, const TArray<FTaskGraphItem>& Prerequisites,const TArray<FTaskGraphItem>& ChildTasks,bool DispatchWhenReady );

	// 创建任务,CreateGraphTask 的简化
	UFUNCTION(BlueprintCallable)
		FTaskGraphItem CreateGraphTaskPure(const FString& ThreadName, bool DispatchWhenReady) {
		return CreateGraphTask(ThreadName, TArray<FTaskGraphItem>(), TArray<FTaskGraphItem>(), DispatchWhenReady);
	}

	// 唤醒挂起的任务
	UFUNCTION(BlueprintCallable)
		void TriggerGraphTask(FTaskGraphItem TaskGraphItem);

	// 用于任务中执行的回调函数
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
		void OnTaskFinished(const FString& message);
}
FTaskGraphItem ATaskGraphActor::CreateGraphTask(const FString& ThreadName, const TArray<FTaskGraphItem>& Prerequisites, const TArray<FTaskGraphItem>& ChildTasks, bool DispatchWhenReady)
{
	FGraphEventArray PrerequisiteEvents;  // 依赖事件
	TArray<TGraphTask<FTaskGraphWithPrerequisitesAndChild>*> ChildGraphTask; // 子任务
	UE_LOG(LogTemp, Warning, TEXT("Task[%s] is Created!"), *ThreadName);
	if (Prerequisites.Num()>0)
	{
		for (FTaskGraphItem item : Prerequisites) // 结构体数组提取依赖事件
		{
			if (item.m_GraphEventRef)
			{
				PrerequisiteEvents.Add(item.m_GraphEventRef); 
				UE_LOG(LogTemp, Warning, TEXT("Task[%s] wait Task[%s]!"), *ThreadName,*item.m_ThreadName);
			}
			else if (item.m_GraphTask)
			{
				PrerequisiteEvents.Add(item.m_GraphTask->GetCompletionEvent());
				UE_LOG(LogTemp, Warning, TEXT("Task[%s] wait Task[%s]!"), *ThreadName,*item.m_ThreadName);
			}
		}
	}
	if (ChildTasks.Num()>0)
	{
		for (FTaskGraphItem item : ChildTasks) // 提取子任务
		{
			if (item.m_GraphTask)
			{
				ChildGraphTask.Add(item.m_GraphTask);
				UE_LOG(LogTemp, Warning, TEXT("Task[%s] is Task[%s] child task!"), *item.m_ThreadName, *ThreadName);
			}
		}
	}

	FGraphTaskDelegate GraphTaskDelegate = FGraphTaskDelegate::CreateUObject(this, &ATaskGraphActor::OnTaskFinished);
	if (DispatchWhenReady)
	{	// 创建立即执行的任务,返回结构体参数
		return FTaskGraphItem(ThreadName, TGraphTask<FTaskGraphWithPrerequisitesAndChild>::CreateTask(&PrerequisiteEvents).ConstructAndDispatchWhenReady(ThreadName, ChildGraphTask, GraphTaskDelegate));
	}
		// 创建任务后挂起,等待触发,返回结构体参数
	return  FTaskGraphItem(ThreadName, nullptr, TGraphTask<FTaskGraphWithPrerequisitesAndChild>::CreateTask(&PrerequisiteEvents).ConstructAndHold(ThreadName, ChildGraphTask, GraphTaskDelegate));
}

void ATaskGraphActor::TriggerGraphTask(FTaskGraphItem TaskGraphItem)
{
	if (TaskGraphItem.m_GraphTask)
	{
		TaskGraphItem.m_GraphTask->Unlock();
		UE_LOG(LogTemp, Warning, TEXT("Task %s Trigger!"), *TaskGraphItem.m_ThreadName);
	}
	
}

参考

标签:TaskGraph,SimpleTask,ThreadName,任务,UE4,多线程,FString,const
来源: https://www.cnblogs.com/shiroe/p/14723592.html