UE4多线代码程片段

这篇博客探讨了两种不同的异步任务处理方式:FNullGraphTask和FRunnable。FNullGraphTask在游戏线程中创建并调度任务,展示了任务队列、加入和结束的时间。而FRunnable通过实现FRunnable接口,创建了一个后台工作线程,用于寻找素数,强调了线程安全和资源管理。这两种技术在游戏开发和高性能计算中有着广泛的应用。
摘要由CSDN通过智能技术生成

FNullGraphTask

//
    #include "Async/TaskGraphInterfaces.h"
    #include "Async/ParallelFor.h"
    
    FString string;
	double StartTime=FPlatformTime::Seconds();
	FGraphEventArray Tasks;
	Tasks.AddZeroed(10);
	ParallelFor(10, [&Tasks](int32 Index) {
		FGraphEventArray InnerTasks;
		InnerTasks.AddZeroed(100);
		ENamedThreads::Type CurrentThread = FTaskGraphInterface::Get().GetCurrentThreadIfKnown();
		for (int32 InnerIndex = 0; InnerIndex < 100; InnerIndex++) {
			InnerTasks[InnerIndex] = TGraphTask<FNullGraphTask>::CreateTask(nullptr, CurrentThread).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::AnyThread);
		}
		Tasks[Index] = TGraphTask<FNullGraphTask>::CreateTask(&InnerTasks, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::AnyThread);
	});
	double QueueTime = FPlatformTime::Seconds();
	string = FString::Printf(TEXT("Tasks QueueTime: %f."),QueueTime-StartTime);
	UE_LOG(LogTemp, Warning, TEXT("%s"), *string);

	FGraphEventRef Join = TGraphTask<FNullGraphTask>::CreateTask(&Tasks, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::AnyThread);
	double JoinTime = FPlatformTime::Seconds();
	string = FString::Printf(TEXT("Tasks JoinTime: %f."), JoinTime - QueueTime);
	UE_LOG(LogTemp, Warning, TEXT("%s"), *string);

	FTaskGraphInterface::Get().WaitUntilTaskCompletes(Join, ENamedThreads::GameThread_Local);
	double EndTime = FPlatformTime::Seconds();
	string = FString::Printf(TEXT("Tasks EndTime: %f."), EndTime - JoinTime);
	UE_LOG(LogTemp, Warning, TEXT("%s"), *string);
LogTemp: Warning: Tasks QueueTime: 0.000470.
LogTemp: Warning: Tasks JoinTime:  0.000152.
LogTemp: Warning: Tasks EndTime:   0.000085.

AsyncTask

#include"Async/AsyncWork.h"

class PrimeCalculationAsyncTask : public FNonAbandonableTask
{
    int32 MaxPrime;

public:
    /*Default constructor*/
    PrimeCalculationAsyncTask(int32 MaxPrime)
    {
        this->MaxPrime = MaxPrime;
    }

    /*This function is needed from the API of the engine. 
    My guess is that it provides necessary information
    about the thread that we occupy and the progress of our task*/
    FORCEINLINE TStatId GetStatId() const
    {
        RETURN_QUICK_DECLARE_CYCLE_STAT(PrimeCalculationAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
    }

    /*This function is executed when we tell our task to execute*/
    void DoWork()
    {
        //TODO:具体耗时的任务 
    }
};
//完成后自动删除操作
 auto task = new FAutoDeleteAsyncTask<PrimeCalculationAsyncTask>(MaxPrime);
 if (task)
 {
     task -> StartBackgroundTask();
 } 

FRunnable

class FPrimeNumberWorker:public FRunnable
{
	/** Singleton instance, can access the thread any time via static accessor, if it is active! */
	static  FPrimeNumberWorker* CRunnable;

	/** Thread to run the worker FRunnable on */
	FRunnableThread* Thread;

	/** The Data Ptr */
	TArray<uint32>* PrimeNumbers;

	/** Stop this thread? Uses Thread Safe Counter */
	FThreadSafeCounter StopTaskCounter;
	//The actual finding of prime numbers
	int32 FindNextPrimeNumber();

private:
	int32				PrimesFoundCount;
	//Constructor / Destructor
	FPrimeNumberWorker(TArray<uint32>& TheArray, const int32 IN_PrimesToFindPerTick);
	virtual ~FPrimeNumberWorker();

public:
	int32				TotalPrimesToFind;

	//Done?
	bool IsFinished() const
	{
		return PrimesFoundCount >= TotalPrimesToFind;
	}

	//~~~ Thread Core Functions ~~~

	
	// Begin FRunnable interface.
	virtual bool Init();
	virtual uint32 Run();
	virtual void Stop();
	// End FRunnable interface

	/** Makes sure this thread has stopped properly */
	void EnsureCompletion();
	//~~~ Starting and Stopping Thread ~~~



	/*
		Start the thread and the worker from static (easy access)!
		This code ensures only 1 Prime Number thread will be able to run at a time.
		This function returns a handle to the newly started instance.
	*/
	static FPrimeNumberWorker* JoyInit(TArray<uint32>& TheArray, const int32 IN_TotalPrimesToFind);
	/** Shuts down the thread. Static so it can easily be called from outside the thread context */
	static void Shutdown();
	static bool IsThreadFinished();
};
#include "PrimeNumberWorker.h"

int32 FPrimeNumberWorker::FindNextPrimeNumber()
{
	//Last known prime number  + 1
	int32 TestPrime = PrimeNumbers->Last();

	bool NumIsPrime = false;

	while (!NumIsPrime)
	{
		NumIsPrime = true;

		//Try Next Number
		TestPrime++;

		//Modulus from 2 to current number - 1 
		for (int32 b = 2; b < TestPrime; b++)
		{
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			//prevent thread from using too many resources
			//FPlatformProcess::Sleep(0.01);
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			if (TestPrime % b == 0)
			{
				NumIsPrime = false;
				break;
				//~~~
			}
		}
	}

	//Success!
	return TestPrime;
}

FPrimeNumberWorker::FPrimeNumberWorker(TArray<uint32>& TheArray, const int32 IN_PrimesToFindPerTick):
	TotalPrimesToFind(IN_PrimesToFindPerTick),StopTaskCounter(0),PrimesFoundCount(0)
{
	//Link to where data should be stored
	PrimeNumbers = &TheArray;

	Thread = FRunnableThread::Create(this, TEXT("FPrimeNumberWorker"), 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more
}

FPrimeNumberWorker::~FPrimeNumberWorker()
{
	delete Thread;
	Thread = NULL;
}

bool FPrimeNumberWorker::Init()
{
	PrimeNumbers->Empty();
	PrimeNumbers->Add(2);
	PrimeNumbers->Add(3);
	return true;
}

uint32 FPrimeNumberWorker::Run()
{
	//Initial wait before starting
	FPlatformProcess::Sleep(0.03);

	//While not told to stop this thread 
	//		and not yet finished finding Prime Numbers
	while (StopTaskCounter.GetValue() == 0 && !IsFinished())
	{
		PrimeNumbers->Add(FindNextPrimeNumber());
		PrimesFoundCount++;

		FPlatformProcess::Sleep(0.01);
	}
	return 0;
}

void FPrimeNumberWorker::Stop()
{
	StopTaskCounter.Increment();
}

void FPrimeNumberWorker::EnsureCompletion()
{
	Stop();
	Thread->WaitForCompletion();
}

FPrimeNumberWorker* FPrimeNumberWorker::JoyInit(TArray<uint32>& TheArray, const int32 IN_TotalPrimesToFind)
{
	if (!CRunnable && FPlatformProcess::SupportsMultithreading())
	{
		CRunnable = new FPrimeNumberWorker(TheArray, IN_TotalPrimesToFind);
	}
	return CRunnable;
}

void FPrimeNumberWorker::Shutdown()
{
	if (CRunnable)
	{
		CRunnable->EnsureCompletion();
		delete CRunnable;
		CRunnable = NULL;
	}
}

bool FPrimeNumberWorker::IsThreadFinished()
{
	if (CRunnable) return CRunnable->IsFinished();
	return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值