版权声明:本文为CSDN博主「wblong_cs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
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
以找素数的任务为例
PrimeCalculationAsyncTask.hpp
#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
以找素数的线程为例
PrimeNumberWorker.h
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();
};
PrimeNumberWorker.cpp
#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;
}